安全设置中增加禁止搜索引擎、禁止爬虫、允许访问的域名等选项

This commit is contained in:
刘祥超
2022-07-07 19:58:30 +08:00
parent dc08847a7d
commit 3605f71f70
5 changed files with 108 additions and 8 deletions

View File

@@ -29,14 +29,14 @@ func (this *IndexAction) RunGet(params struct{}) {
} }
// 国家和地区 // 国家和地区
countryMaps := []maps.Map{} var countryMaps = []maps.Map{}
for _, countryId := range config.AllowCountryIds { for _, countryId := range config.AllowCountryIds {
countryResp, err := this.RPC().RegionCountryRPC().FindEnabledRegionCountry(this.AdminContext(), &pb.FindEnabledRegionCountryRequest{RegionCountryId: countryId}) countryResp, err := this.RPC().RegionCountryRPC().FindEnabledRegionCountry(this.AdminContext(), &pb.FindEnabledRegionCountryRequest{RegionCountryId: countryId})
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
return return
} }
country := countryResp.RegionCountry var country = countryResp.RegionCountry
if country != nil { if country != nil {
countryMaps = append(countryMaps, maps.Map{ countryMaps = append(countryMaps, maps.Map{
"id": country.Id, "id": country.Id,
@@ -47,14 +47,14 @@ func (this *IndexAction) RunGet(params struct{}) {
this.Data["countries"] = countryMaps this.Data["countries"] = countryMaps
// 省份 // 省份
provinceMaps := []maps.Map{} var provinceMaps = []maps.Map{}
for _, provinceId := range config.AllowProvinceIds { for _, provinceId := range config.AllowProvinceIds {
provinceResp, err := this.RPC().RegionProvinceRPC().FindEnabledRegionProvince(this.AdminContext(), &pb.FindEnabledRegionProvinceRequest{RegionProvinceId: provinceId}) provinceResp, err := this.RPC().RegionProvinceRPC().FindEnabledRegionProvince(this.AdminContext(), &pb.FindEnabledRegionProvinceRequest{RegionProvinceId: provinceId})
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
return return
} }
province := provinceResp.RegionProvince var province = provinceResp.RegionProvince
if province != nil { if province != nil {
provinceMaps = append(provinceMaps, maps.Map{ provinceMaps = append(provinceMaps, maps.Map{
"id": province.Id, "id": province.Id,
@@ -76,6 +76,11 @@ func (this *IndexAction) RunPost(params struct {
AllowIPs []string AllowIPs []string
AllowRememberLogin bool AllowRememberLogin bool
DenySearchEngines bool
DenySpiders bool
DomainsJSON []byte
Must *actions.Must Must *actions.Must
CSRF *actionutils.CSRF CSRF *actionutils.CSRF
}) { }) {
@@ -91,7 +96,7 @@ func (this *IndexAction) RunPost(params struct {
config.Frame = params.Frame config.Frame = params.Frame
// 国家和地区 // 国家和地区
countryIds := []int64{} var countryIds = []int64{}
if len(params.CountryIdsJSON) > 0 { if len(params.CountryIdsJSON) > 0 {
err = json.Unmarshal(params.CountryIdsJSON, &countryIds) err = json.Unmarshal(params.CountryIdsJSON, &countryIds)
if err != nil { if err != nil {
@@ -102,7 +107,7 @@ func (this *IndexAction) RunPost(params struct {
config.AllowCountryIds = countryIds config.AllowCountryIds = countryIds
// 省份 // 省份
provinceIds := []int64{} var provinceIds = []int64{}
if len(params.ProvinceIdsJSON) > 0 { if len(params.ProvinceIdsJSON) > 0 {
err = json.Unmarshal(params.ProvinceIdsJSON, &provinceIds) err = json.Unmarshal(params.ProvinceIdsJSON, &provinceIds)
if err != nil { if err != nil {
@@ -128,6 +133,20 @@ func (this *IndexAction) RunPost(params struct {
// 允许本地 // 允许本地
config.AllowLocal = params.AllowLocal config.AllowLocal = params.AllowLocal
// 禁止搜索引擎和爬虫
config.DenySearchEngines = params.DenySearchEngines
config.DenySpiders = params.DenySpiders
// 允许的域名
var domains = []string{}
if len(params.DomainsJSON) > 0 {
err = json.Unmarshal(params.DomainsJSON, &domains)
if err != nil {
this.Fail("解析允许访问的域名失败:" + err.Error())
}
}
config.AllowDomains = domains
// 允许记住登录 // 允许记住登录
config.AllowRememberLogin = params.AllowRememberLogin config.AllowRememberLogin = params.AllowRememberLogin

View File

@@ -75,6 +75,13 @@ func (this *userMustAuth) BeforeAction(actionPtr actions.ActionWrapper, paramNam
return false return false
} }
// 检查请求
if !checkRequestSecurity(securityConfig, action.Request) {
action.ResponseWriter.WriteHeader(http.StatusForbidden)
return false
}
// 检查系统是否已经配置过 // 检查系统是否已经配置过
if !setup.IsConfigured() { if !setup.IsConfigured() {
action.RedirectURL("/setup") action.RedirectURL("/setup")

View File

@@ -22,7 +22,7 @@ func (this *UserShouldAuth) BeforeAction(actionPtr actions.ActionWrapper, paramN
this.action = actionPtr.Object() this.action = actionPtr.Object()
// 安全相关 // 安全相关
action := this.action var action = this.action
securityConfig, _ := configloaders.LoadSecurityConfig() securityConfig, _ := configloaders.LoadSecurityConfig()
if securityConfig == nil { if securityConfig == nil {
action.AddHeader("X-Frame-Options", "SAMEORIGIN") action.AddHeader("X-Frame-Options", "SAMEORIGIN")
@@ -42,6 +42,12 @@ func (this *UserShouldAuth) BeforeAction(actionPtr actions.ActionWrapper, paramN
return false return false
} }
// 检查请求
if !checkRequestSecurity(securityConfig, action.Request) {
action.ResponseWriter.WriteHeader(http.StatusForbidden)
return false
}
return true return true
} }

View File

@@ -9,6 +9,8 @@ import (
"github.com/iwind/TeaGo/lists" "github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/logs" "github.com/iwind/TeaGo/logs"
"net" "net"
"net/http"
"regexp"
"sync" "sync"
) )
@@ -106,3 +108,41 @@ func checkIPWithoutCache(config *systemconfigs.SecurityConfig, ipAddr string) bo
return true return true
} }
// 请求检查相关正则
var searchEngineRegex = regexp.MustCompile(`60spider|adldxbot|adsbot-google|applebot|admantx|alexa|baidu|bingbot|bingpreview|facebookexternalhit|googlebot|proximic|slurp|sogou|twitterbot|yandex`)
var spiderRegexp = regexp.MustCompile(`python|pycurl|http-client|httpclient|apachebench|nethttp|http_request|java|perl|ruby|scrapy|php|rust|curl|wget`) // 其中增加了curl和wget
// 检查请求
func checkRequestSecurity(securityConfig *systemconfigs.SecurityConfig, req *http.Request) bool {
if securityConfig == nil {
return true
}
var userAgent = req.UserAgent()
var referer = req.Referer()
// 检查搜索引擎
if securityConfig.DenySearchEngines && (len(userAgent) == 0 || searchEngineRegex.MatchString(userAgent) || (len(referer) > 0 && searchEngineRegex.MatchString(referer))) {
return false
}
// 检查爬虫
if securityConfig.DenySpiders && (len(userAgent) == 0 || spiderRegexp.MatchString(userAgent) || (len(referer) > 0 && spiderRegexp.MatchString(referer))) {
return false
}
// 检查允许访问的域名
if len(securityConfig.AllowDomains) > 0 {
var domain = req.Host
realDomain, _, err := net.SplitHostPort(domain)
if err == nil && len(realDomain) > 0 {
domain = realDomain
}
if !lists.ContainsString(securityConfig.AllowDomains, domain) {
return false
}
}
return true
}

View File

@@ -40,7 +40,7 @@
<td>允许局域网访问</td> <td>允许局域网访问</td>
<td> <td>
<checkbox name="allowLocal" v-model="config.allowLocal"></checkbox> <checkbox name="allowLocal" v-model="config.allowLocal"></checkbox>
<p class="comment">选中表示允许在本机和局域网访问。</p> <p class="comment">选中表示总是允许在本机和局域网访问,不需要其他限制条件</p>
</td> </td>
</tr> </tr>
<tr> <tr>
@@ -50,6 +50,34 @@
<p class="comment">选中表示允许在登录界面可以选择记住登录。</p> <p class="comment">选中表示允许在登录界面可以选择记住登录。</p>
</td> </td>
</tr> </tr>
<tr>
<td colspan="2">
<more-options-indicator></more-options-indicator>
</td>
</tr>
<tbody v-show="moreOptionsVisible">
<tr>
<td>禁止搜索引擎</td>
<td>
<checkbox name="denySearchEngines" v-model="config.denySearchEngines"></checkbox>
<p class="comment">禁止常见的搜索引擎访问。</p>
</td>
</tr>
<tr>
<td>禁止爬虫</td>
<td>
<checkbox name="denySpiders" v-model="config.denySpiders"></checkbox>
<p class="comment">禁止常见的爬虫访问。</p>
</td>
</tr>
<tr>
<td>允许访问的域名</td>
<td>
<domains-box :v-domains="config.allowDomains"></domains-box>
<p class="comment">只允许通过这些域名或者IP作为主机地址访问当前管理系统不填表示没有限制。</p>
</td>
</tr>
</tbody>
</table> </table>
<submit-btn></submit-btn> <submit-btn></submit-btn>
</form> </form>