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

Refs https://github.com/1Panel-dev/1Panel/issues/3906
pull/5482/head
zhengkunwang 5 months ago committed by GitHub
parent b428d818e7
commit b36e2c5676
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

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

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

@ -754,7 +754,7 @@ func (w WebsiteService) GetWebsiteHTTPS(websiteId uint) (response.WebsiteHTTPS,
} else { } else {
res.HttpConfig = constant.HTTPToHTTPS 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 { if err != nil {
return res, err return res, err
} }
@ -765,6 +765,9 @@ func (w WebsiteService) GetWebsiteHTTPS(websiteId uint) (response.WebsiteHTTPS,
if p.Name == "ssl_ciphers" { if p.Name == "ssl_ciphers" {
res.Algorithm = p.Params[0] 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 return res, nil
} }
@ -782,7 +785,7 @@ func (w WebsiteService) OpWebsiteHTTPS(ctx context.Context, req request.WebsiteH
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err = ChangeHSTSConfig(req.Enable, nginxInstall, website); err != nil { if err = ChangeHSTSConfig(req.Hsts, nginxInstall, website); err != nil {
return nil, err return nil, err
} }
res.Enable = req.Enable 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_pass", []string{req.ProxyPass})
location.UpdateDirective("proxy_set_header", []string{"Host", req.ProxyHost}) 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) location.ChangePath(req.Modifier, req.Match)
if req.Cache { if req.Cache {
location.AddCache(req.CacheTime, req.CacheUnit) location.AddCache(req.CacheTime, req.CacheUnit)

@ -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 { if err := nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
return err return err
} }
@ -630,6 +634,13 @@ func applySSL(website model.Website, websiteSSL model.WebsiteSSL, req request.We
nginxParams[i].Params = []string{req.Algorithm} 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 { if err := updateNginxConfig(constant.NginxScopeServer, nginxParams, &website); err != nil {
return err return err
} }

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

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

@ -2026,6 +2026,7 @@ const message = {
websiteBackupWarn: websiteBackupWarn:
'Only supports importing local backups, importing backups from other machines may cause recovery failure', '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', 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: { php: {
short_open_tag: 'Short tag support', short_open_tag: 'Short tag support',

@ -1887,6 +1887,7 @@ const message = {
rewriteHelper2: ' WordPress ', rewriteHelper2: ' WordPress ',
websiteBackupWarn: '', websiteBackupWarn: '',
ipWebsiteWarn: 'IP ', ipWebsiteWarn: 'IP ',
hstsHelper: ' HSTS ',
}, },
php: { php: {
short_open_tag: '', short_open_tag: '',

@ -1888,6 +1888,7 @@ const message = {
rewriteHelper2: ' WordPress ', rewriteHelper2: ' WordPress ',
websiteBackupWarn: '', websiteBackupWarn: '',
ipWebsiteWarn: 'IP 访', ipWebsiteWarn: 'IP 访',
hstsHelper: ' HSTS ',
}, },
php: { php: {
short_open_tag: '', short_open_tag: '',

@ -22,6 +22,10 @@
<el-option :label="$t('website.HTTPSOnly')" :value="'HTTPSOnly'"></el-option> <el-option :label="$t('website.HTTPSOnly')" :value="'HTTPSOnly'"></el-option>
</el-select> </el-select>
</el-form-item> </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-form-item :label="$t('website.sslConfig')" prop="type">
<el-select v-model="form.type" @change="changeType(form.type)"> <el-select v-model="form.type" @change="changeType(form.type)">
<el-option :label="$t('website.oldSSL')" :value="'existed'"></el-option> <el-option :label="$t('website.oldSSL')" :value="'existed'"></el-option>
@ -190,6 +194,7 @@ const form = reactive({
privateKeyPath: '', privateKeyPath: '',
certificatePath: '', certificatePath: '',
httpConfig: 'HTTPToHTTPS', httpConfig: 'HTTPToHTTPS',
hsts: true,
algorithm: 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', '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'], SSLProtocol: ['TLSv1.3', 'TLSv1.2', 'TLSv1.1', 'TLSv1'],
@ -199,6 +204,7 @@ const ssls = ref();
const acmeAccounts = ref(); const acmeAccounts = ref();
const websiteSSL = ref(); const websiteSSL = ref();
const rules = ref({ const rules = ref({
hsts: [Rules.requiredInput],
type: [Rules.requiredSelect], type: [Rules.requiredSelect],
privateKey: [Rules.requiredInput], privateKey: [Rules.requiredInput],
certificate: [Rules.requiredInput], certificate: [Rules.requiredInput],
@ -285,6 +291,7 @@ const get = () => {
websiteSSL.value = res.data.SSL; websiteSSL.value = res.data.SSL;
form.acmeAccountID = res.data.SSL.acmeAccountId; form.acmeAccountID = res.data.SSL.acmeAccountId;
} }
form.hsts = res.data.hsts;
} }
listSSL(); listSSL();
listAcmeAccount(); listAcmeAccount();

Loading…
Cancel
Save