Browse Source

feat:网站 HTTPS 增加 HSTS 配置 (#5463)

Refs https://github.com/1Panel-dev/1Panel/issues/3906
pull/5482/head
zhengkunwang 5 months ago committed by GitHub
parent
commit
b36e2c5676
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      backend/app/dto/request/website.go
  2. 1
      backend/app/dto/response/website.go
  3. 10
      backend/app/service/website.go
  4. 11
      backend/app/service/website_utils.go
  5. 1
      cmd/server/nginx_conf/ssl.conf
  6. 1
      frontend/src/api/interface/website.ts
  7. 1
      frontend/src/lang/modules/en.ts
  8. 1
      frontend/src/lang/modules/tw.ts
  9. 1
      frontend/src/lang/modules/zh.ts
  10. 7
      frontend/src/views/website/website/config/basic/https/index.vue

1
backend/app/dto/request/website.go

@ -123,6 +123,7 @@ type WebsiteHTTPSOp struct {
HttpConfig string `json:"httpConfig" validate:"oneof=HTTPSOnly HTTPAlso HTTPToHTTPS"`
SSLProtocol []string `json:"SSLProtocol"`
Algorithm string `json:"algorithm"`
Hsts bool `json:"hsts"`
}
type WebsiteNginxUpdate struct {

1
backend/app/dto/response/website.go

@ -37,6 +37,7 @@ type WebsiteHTTPS struct {
SSL model.WebsiteSSL `json:"SSL"`
SSLProtocol []string `json:"SSLProtocol"`
Algorithm string `json:"algorithm"`
Hsts bool `json:"hsts"`
}
type WebsiteLog struct {

10
backend/app/service/website.go

@ -754,7 +754,7 @@ func (w WebsiteService) GetWebsiteHTTPS(websiteId uint) (response.WebsiteHTTPS,
} else {
res.HttpConfig = constant.HTTPToHTTPS
}
params, err := getNginxParamsByKeys(constant.NginxScopeServer, []string{"ssl_protocols", "ssl_ciphers"}, &website)
params, err := getNginxParamsByKeys(constant.NginxScopeServer, []string{"ssl_protocols", "ssl_ciphers", "add_header"}, &website)
if err != nil {
return res, err
}
@ -765,6 +765,9 @@ func (w WebsiteService) GetWebsiteHTTPS(websiteId uint) (response.WebsiteHTTPS,
if p.Name == "ssl_ciphers" {
res.Algorithm = p.Params[0]
}
if p.Name == "add_header" && len(p.Params) > 0 && p.Params[0] == "Strict-Transport-Security" {
res.Hsts = true
}
}
return res, nil
}
@ -782,7 +785,7 @@ func (w WebsiteService) OpWebsiteHTTPS(ctx context.Context, req request.WebsiteH
if err != nil {
return nil, err
}
if err = ChangeHSTSConfig(req.Enable, nginxInstall, website); err != nil {
if err = ChangeHSTSConfig(req.Hsts, nginxInstall, website); err != nil {
return nil, err
}
res.Enable = req.Enable
@ -1616,9 +1619,6 @@ func (w WebsiteService) OperateProxy(req request.WebsiteProxyConfig) (err error)
}
location.UpdateDirective("proxy_pass", []string{req.ProxyPass})
location.UpdateDirective("proxy_set_header", []string{"Host", req.ProxyHost})
if website.Protocol == constant.ProtocolHTTPS {
location.UpdateDirective("add_header", []string{"Strict-Transport-Security", "\"max-age=31536000\""})
}
location.ChangePath(req.Modifier, req.Match)
if req.Cache {
location.AddCache(req.CacheTime, req.CacheUnit)

11
backend/app/service/website_utils.go

@ -609,6 +609,10 @@ func applySSL(website model.Website, websiteSSL model.WebsiteSSL, req request.We
}
}
if !req.Hsts {
server.RemoveDirective("add_header", []string{"Strict-Transport-Security", "\"max-age=31536000\""})
}
if err := nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
return err
}
@ -630,6 +634,13 @@ func applySSL(website model.Website, websiteSSL model.WebsiteSSL, req request.We
nginxParams[i].Params = []string{req.Algorithm}
}
}
if req.Hsts {
nginxParams = append(nginxParams, dto.NginxParam{
Name: "add_header",
Params: []string{"Strict-Transport-Security", "\"max-age=31536000\""},
})
}
if err := updateNginxConfig(constant.NginxScopeServer, nginxParams, &website); err != nil {
return err
}

1
cmd/server/nginx_conf/ssl.conf

@ -5,7 +5,6 @@ ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDS
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
add_header Strict-Transport-Security "max-age=31536000";
error_page 497 https://$host$request_uri;
proxy_set_header X-Forwarded-Proto https;
ssl_stapling on;

1
frontend/src/api/interface/website.ts

@ -263,6 +263,7 @@ export namespace Website {
httpConfig: string;
SSLProtocol: string[];
algorithm: string;
hsts: boolean;
}
export interface CheckReq {

1
frontend/src/lang/modules/en.ts

@ -2026,6 +2026,7 @@ const message = {
websiteBackupWarn:
'Only supports importing local backups, importing backups from other machines may cause recovery failure',
ipWebsiteWarn: 'Websites with IP as domain names need to be set as default sites to be accessed normally',
hstsHelper: 'Enabling HSTS can increase website security',
},
php: {
short_open_tag: 'Short tag support',

1
frontend/src/lang/modules/tw.ts

@ -1887,6 +1887,7 @@ const message = {
rewriteHelper2: '從應用程式商店安裝的 WordPress 等應用預設已經配置好偽靜態重複配置可能會報錯',
websiteBackupWarn: '僅支援導入本機備份導入其他機器備份可能會恢復失敗',
ipWebsiteWarn: 'IP 為網域名稱的網站需要設定為預設網站才能正常存取',
hstsHelper: '開啟 HSTS 可以增加網站安全性',
},
php: {
short_open_tag: '短標簽支持',

1
frontend/src/lang/modules/zh.ts

@ -1888,6 +1888,7 @@ const message = {
rewriteHelper2: '从应用商店安装的 WordPress 等应用默认已经配置好伪静态重复配置可能会报错',
websiteBackupWarn: '仅支持导入本机备份导入其他机器备份可能会恢复失败',
ipWebsiteWarn: 'IP 为域名的网站需要设置为默认站点才能正常访问',
hstsHelper: '开启 HSTS 可以增加网站安全性',
},
php: {
short_open_tag: '短标签支持',

7
frontend/src/views/website/website/config/basic/https/index.vue

@ -22,6 +22,10 @@
<el-option :label="$t('website.HTTPSOnly')" :value="'HTTPSOnly'"></el-option>
</el-select>
</el-form-item>
<el-form-item :label="'HSTS'" prop="hsts">
<el-checkbox v-model="form.hsts">{{ $t('commons.button.start') }}</el-checkbox>
<span class="input-help">{{ $t('website.hstsHelper') }}</span>
</el-form-item>
<el-form-item :label="$t('website.sslConfig')" prop="type">
<el-select v-model="form.type" @change="changeType(form.type)">
<el-option :label="$t('website.oldSSL')" :value="'existed'"></el-option>
@ -190,6 +194,7 @@ const form = reactive({
privateKeyPath: '',
certificatePath: '',
httpConfig: 'HTTPToHTTPS',
hsts: true,
algorithm:
'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:!aNULL:!eNULL:!EXPORT:!DSS:!DES:!RC4:!3DES:!MD5:!PSK:!KRB5:!SRP:!CAMELLIA:!SEED',
SSLProtocol: ['TLSv1.3', 'TLSv1.2', 'TLSv1.1', 'TLSv1'],
@ -199,6 +204,7 @@ const ssls = ref();
const acmeAccounts = ref();
const websiteSSL = ref();
const rules = ref({
hsts: [Rules.requiredInput],
type: [Rules.requiredSelect],
privateKey: [Rules.requiredInput],
certificate: [Rules.requiredInput],
@ -285,6 +291,7 @@ const get = () => {
websiteSSL.value = res.data.SSL;
form.acmeAccountID = res.data.SSL.acmeAccountId;
}
form.hsts = res.data.hsts;
}
listSSL();
listAcmeAccount();

Loading…
Cancel
Save