# 服务器安全

# Linux防火墙操作

在Centos linux 6及以前的版本,操控防火墙用的命令是iptables,但在Centos linux 7 及其以后的版本,操控防火墙的命令变化了,现在用firewall-cmd这个命令来操作防火墙

参考: https://blog.csdn.net/xqhys/article/details/81837517

# CentOS 6 (iptables)

# 开启端口
iptables -I INPUT -p tcp --dport 8080 -j ACCEPT
# 关闭端口
iptables -I INPUT -p tcp --dport 8080 -j DROP
# 保存修改 或 service iptables save
/etc/init.d/iptables save
# 重启防火墙,修改生效
service iptables restart

# 查看端口状态
/etc/init.d/iptables status
#显示规则列表
iptables -nvL
# 关闭防火墙
chkconfig –level 35 iptables off
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# CentOS 7 (firewall-cmd)

# 永久开放端口
firewall-cmd --zone=public --add-port=8080/tcp --permanent
# 永久关闭端口
firewall-cmd --zone=public --remove-port=8080/tcp --permanent 
# 刷新规则用 --reload
firewall-cmd --reload
# 查询端口是否开放用 --query-port
firewall-cmd --zone=public --query-port=8080/tcp

#启动 firewalld.service服务
service firewalld start
#停止firewalld.service服务
service firewalld stop
#重启firewalld.service服务
service firewalld restart
#查看firewall的状态
firewall-cmd --state
#查看防火墙已有规则列表
firewall-cmd --list-all
#查看firewall服务状态
systemctl status firewalld
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

注意在Centos7也可同时使用iptables开启防火墙,例如Docker容器的网络端口默认采用iptables来控制,如果要使用iptables操控防火墙,需要先关闭firewalld防火墙

#关闭firewall
systemctl stop firewalld
#允许开机启动iptables
systemctl enable iptables
#启动iptables
systemctl start iptables
#查看iptables状态
systemctl status iptables
#其他开放、禁用端口操作与centos6中iptables操作相同
1
2
3
4
5
6
7
8
9

# Ubuntu (ufw)

为了简化iptables (opens new window)设置,ubuntu提供了一个名为ufw的工具

# 安装ufw
sudo apt-get install ufw
# 开启
sudo ufw enable
# 关闭
sudo ufw diable
#防火墙开启后,使用如下命令,设置一个缺省策略:deny是默认拒绝一切请求,allow是默认接收一切请求。
sudo ufw default deny
# 开放访问权限给指定主机IP
sudo ufw allow from 192.168.1.66
# 看下添加后的策略
sudo ufw status
# 开放端口
sudo ufw allow 80/tcp
# 关闭端口
sudo ufw delete allow 80/tcp
# 策略修改过后,要使用reload重启生效
sudo ufw reload
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# Ubuntu (iptables)

若系统中没有ufw命令,则使用iptables

  1. Ubuntu 默认有装iptables,可通过dpkg -l或which iptables确认
  2. Ubuntu默认没有iptables配置文件,需通过iptables-save > /etc/network/iptables.up.rules生成
  3. iptables配置文件路径及文件名建议为/etc/network/iptables.up.rules,因为执行iptables-apply默认指向该文件,也可以通过-w参数指定文件
  4. Ubuntu 没有重启iptables的命令,执行iptables-apply生效
  5. Ubuntu iptables默认重启服务器后清空,需在/etc/network/interfaces里写入pre-up iptables-restore < /etc/network/iptables.up.rules才会开机生效
# 允许所有访问22端口:
iptables -A INPUT -p tcp --dport 8080 -j ACCEPT
# 拒绝所有访问22端口:
iptables -A INPUT -p tcp --dport 8080 -j DROP
#保存策略到指定文件(后面文件路径及文件名可自定义)
iptables-save > /etc/network/iptables.up.rules
# 应用策略:输入y
iptables-apply
#删除策略(需先cat /etc/network/iptables.up.rules确认删除第几行,或者直接操作/etc/network/iptables.up.rules文件也行)
iptables -D INPUT 2
1
2
3
4
5
6
7
8
9
10

# 安全漏洞修复总结

# Content-Security-Policy头缺失(无法彻底解决)

通过添加配置igs.security-headers-enabled = true 来开启安全头

    @ConditionalOnExpression(value = "'${server.ssl.enabled}' == 'true' || '${igs.security-headers-enabled}' == 'true'")
    @Bean
    public FilterRegistrationBean<HttpsSecurityHeaderFilter> httpsSecurityHeaderFilter() {
        FilterRegistrationBean<HttpsSecurityHeaderFilter> bean = new FilterRegistrationBean<>();
        bean.addUrlPatterns("/*");
        bean.setFilter(new HttpsSecurityHeaderFilter());
        return bean;
    }
1
2
3
4
5
6
7
8

igs中支持通过添加配置项igs.security-headers-enabled = true来开启CSP头

# 检测请求携带的Referer是否同域,预防CSRF攻击

判断当前请求携带的Referer是否同域,不同域直接拦截过滤

 if (referer == null || !referer.contains(serverName)) {
            log.error("Referer过滤器 服务器:{} 当前域名:{}", serverName, referer);
            HttpServletResponse resp = (HttpServletResponse) servletResponse;
            resp.setStatus(HttpStatus.NOT_FOUND.value());
            return;
        } else {
            filterChain.doFilter(servletRequest, servletResponse);
        }
1
2
3
4
5
6
7
8

igs中支持通过配置项csrf.enabled设置为true或是false来开启或关闭过滤器

# API成批分配

在反序列化的时候请求参数中包含了非必须属性,需加以判断

在Json工具类中添加严格的反序列化对象strictObjectMapper,旨在判断请求体中的参数是否和所要反序列化的对象的属性一一对应

   /**
     * 严格的ObjectMapper,不带忽略失败的配置
     */
    @Getter(lazy = true)
    private final static ObjectMapper strictObjectMapper = new ObjectMapper();
1
2
3
4
5

在需要反序列化的地方添加如下代码,若未抛出异常,则请求体参数和对象属性对应。以此避免请求体中包含额外的参数却反序列化成功

   public AjaxResult login(@RequestBody String loginBody) {
       // 检测请求体中的参数
       LoginBody strictLoginBody;
       try {
           strictLoginBody = JsonUtils.getStrictObjectMapper().readValue(loginBody, LoginBody.class);
       } catch (JsonProcessingException e) {
           throw new BadRequestException("请求参数不合法");
       }
   }
1
2
3
4
5
6
7
8
9

# 具有不安全,不正确或缺少SameSite属性的Cookie

设置Cookie的SameSite属性为strict

    session:
      cookie:
        name: IGSERVER_UID
        http-only: true
        same-site: strict
1
2
3
4
5

# SRI检查

如下链接是在网页中引用谷歌字体,是否引用该字体并不会对页面显示造成影响,可直接删除

https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700
1

# 查询中的密码参数

请求参数中包含敏感信息字段(keyword),易被窃取,需修改字段名

 public PagedListResult<ServiceDto> getPagedList(
            @RequestParam(value = "keyword", required = false) String keyword,
            @RequestParam(value = "serviceType", required = false) String serviceType,
            @RequestParam(value = "dataSourceTypes", required = false) String dataSourceTypes,
            @RequestParam(value = "serviceStatus", required = false) String serviceStatus,
 )
1
2
3
4
5
6
      const params = {
        keyword: this.searchForm.keyWords,
        protocolTypes: serviceTypeStr,
        serviceStatus: serviceStatus,
        pageSize: this.pagination.pageSize
      }
1
2
3
4
5
6

只需修改keyword名称,避免敏感信息即可

# 已解密的登录请求

请求参数中包含敏感信息时,开启 SSL

server.ssl.enabled=true
1

igs 中支持通过配置项server.ssl.enabled=true来开启 SSL

# 登录消息错误凭证枚举

统一在用户名字段无效和密码字段无效时的错误消息,统一将错误信息更改为"用户不存在/密码错误"

if (StringUtils.isNull(user)) {
    recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.not.exists"));
    throw new ServiceException(MessageUtils.message("user.password.not.match"));
}
1
2
3
4
public UserPasswordNotMatchException(String[] errorInfo) {
    super("user.password.not.match", errorInfo);
}
1
2
3

# 检测到隐藏目录

请求url:http://192.168.82.177:8089/igs/manager/

该页面为IGServer的首页,不可屏蔽,否则会导致某些功能不可用(难以定位到服务发布,登录等页面)

# "Content-Security-Policy" 头中缺少 "Script-Src" 策略或策略不安全

这里csp的配置为:Content-Security-Policy: default-src 'self' http:; font-src 'self' http: data:; img-src 'self' http: data:; object-src 'none'; script-src 'self'; style-src 'self'

若配置为Script-Src 'none'则表示为不加载任何js脚本内容,会导致初始为空白页,登录功能不可用

# SQL注入/发现数据库错误模式

将logs下面的日志文件内容清空,日志中出现与数据库连接或是查询相关的错误会报SQLError导致SQL注入攻击,只需将logs下的日志文件内容清空即可。

# 跨帧脚本编制防御缺失或不安全

添加过滤器,在添加的过滤器中设置"X-Frame-Options"的属性为SAMEORIGIN

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        MapgisCloudProperties mapgisCloudProperties = SpringUtil.getBean(MapgisCloudProperties.class);
        response.addHeader("X-Frame-Options", "SAMEORIGIN");
        if("/config".equals(request.getServletPath())){
            response.setStatus(HttpStatus.BAD_REQUEST.value());
        }
1
2
3
4
5
6
7
8

# springboot env 未授权访问

云管中配置文件application.properties文件中添加

management.endpoint.env.enabled=false
1

也可将其他非必要的管理类接口均关闭

management.endpoints.web.exposure.include=info,health
1

# 禁止访问到swagger-ui

云管中application.properties文件中添加配置

springdoc.api-docs.enabled=false
springdoc.swagger-ui.enabled=false
1
2

# druid未授权访问

云管中application.properties文件中添加配置

spring.datasource.druid.stat-view-servlet.enabled=false
1

如需访问则添加,其中用户名密码都为root

spring.datasource.druid.stat-view-servlet.enabled=true
spring.datasource.druid.stat-view-servlet.allow=
1
2