10种常见的安全漏洞问题
前言
我们日常开发中,很多小伙伴容易忽视安全漏洞问题,认为只要正常实现业务逻辑就可以了。其实,安全性才是最重要的。本文将跟大家一起学习常见的安全漏洞问题,希望对大家有帮助哈。
1. SQL 注入
1.1 什么是 SQL 注入
SQL 注入是一种代码注入技术,一般被应用于攻击 web 应用程序。它通过在 web 应用接口传入一些特殊参数字符,来欺骗应用服务器,执行恶意的 SQL 命令,以达到非法获取系统信息的目的。它目前是黑客对数据库进行攻击的最常用手段之一。
1.2 SQL 注入是如何攻击的
举个常见的业务场景:在 web 表单搜索框输入员工名字,然后后台查询出对应名字的员工。
这种场景下,一般都是前端页面把一个名字参数 name 传到后台,然后后台通过 SQL 把结果查询出来。
name = "田螺"; //前端传过来的
SQL= "select * from staff where name=" + name; //根据前端传过来的name参数,查询数据库员工表staff
因为 SQL 是直接拼接的,如果我们完全信任前端传的参数的话。假如前端传这么一个参数时'' or '1'='1',SQL 就变成酱紫的啦。
select * from staff where name='' or '1'='1';
这个 SQL 会把所有的员工信息全都查出来了,酱紫请求用户已经越权啦。请求者可以获取所有员工的信息,其他用户信息已经暴露了。
1.3 如何预防 SQL 注入问题
1.3.1 使用 #{} 而不是 ${}
在 MyBatis 中,使用#{}而不是${},可以很大程度防止 sql 注入。
★
- 因为#{}是一个参数占位符,对于字符串类型,会自动加上"",其他类型不加。由于 Mybatis 采用预编译,其后的参数不会再进行 SQL 编译,所以一定程度上防止 SQL 注入。
- ${}是一个简单的字符串替换,字符串是什么,就会解析成什么,存在 SQL 注入风险。
”
1.3.2 不要暴露一些不必要的日志或者安全信息,比如避免直接响应一些 sql 异常信息
如果 SQL 发生异常了,不要把这些信息暴露响应给用户,可以自定义异常进行响应。
1.3.3 不相信任何外部输入参数,过滤参数中含有的一些数据库关键词
可以加个参数校验过滤的方法,过滤union,or等数据库关键词。
1.3.4 适当的权限控制
在你查询信息时,先校验下当前用户是否有这个权限。比如说,实现代码的时候,可以让用户多传一个企业 id 什么的,或者获取当前用户的 session 信息等,在查询前,先校验一下当前用户是否是这个企业下的等等,是的话才有这个查询员工的权限。
2. JSON 反序列化漏洞——如 Fastjson 安全漏洞
2.1 什么是 JSON 序列化,JSON 反序列化
- 序列化:把对象转换为字节序列的过程。
- 反序列:把字节序列恢复为 Java 对象的过程。
Json 序列化就是将对象转换成 Json 格式的字符串,JSON 反序列化就是 Json 串转换成对象。
2.2 JSON 反序列化漏洞是如何被攻击
不安全的反序列化可以导致远程代码执行、重放攻击、注入攻击或特权升级攻击。之前 Fastjson 频繁爆出安全漏洞,我们现在分析 fastjson 1.2.24 版本的一个反序列化漏洞吧,这个漏洞比较常见的利用手法就是通过 jndi 注入的方式实现 RCE。
我们先来看 fastjson 一个反序列化的简单例子:
public class User {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("调用了name方法");
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
System.out.println("调用了age方法");
this.age = age;
}
public static void main(String[] args) {
String str = "{\"@type\":\"cn.eovie.bean.User\",\"age\":26,\"name\":\"捡田螺的小男孩\"}";
User user = JSON.parseObject(str,User.class);
}
}
运行结果:
调用了age方法
调用了name方法
加了@type属性就能调用对应对象的setXXX方法,而@type表示指定反序列化成某个类。如果我们能够找到一个类,而这个类的某个setXXX方法中通过我们的精心构造能够完成命令执行,即可达到攻击的目的啦。
★
com.sun.rowset.JdbcRowSetImpl 就是类似这么一个类,它有两个 set 方法,分别是 setAutoCommit 和 setDataSourceName。
”
有兴趣的小伙伴,可以看下它的源代码:
public void setDataSourceName(String var1) throws SQLException {
if (this.getDataSourceName() != null) {
if (!this.getDataSourceName().equals(var1)) {
super.setDataSourceName(var1);
this.conn = null;
this.ps = null;
this.rs = null;
}
} else {
super.setDataSourceName(var1);
}
}
public void setAutoCommit(boolean var1) throws SQLException {
if (this.conn != null) {
this.conn.setAutoCommit(var1);
} else {
this.conn = this.connect();
this.conn.setAutoCommit(var1);
}
}
private Connection connect() throws SQLException {
if (this.conn != null) {
return this.conn;
} else if (this.getDataSourceName() != null) {
try {
InitialContext var1 = new InitialContext();
DataSource var2 = (DataSource)var1.lookup(this.getDataSourceName());
return this.getUsername() != null && !this.getUsername().equals("") ? var2.getConnection(this.getUsername(), this.getPassword()) : var2.getConnection();
} catch (NamingException var3) {
throw new SQLException(this.resBundle.handleGetObject("jdbcrowsetimpl.connect").toString());
}
} else {
return this.getUrl() != null ? DriverManager.getConnection(this.getUrl(), this.getUsername(), this.getPassword()) : null;
}
}
setDataSourceName 简单设置了 dataSourceName 的值,setAutoCommit中有 connect 操作,connect 方法中有典型的 jndi 的lookup方法调用,参数刚好就是在setDataSourceName中设置的 dataSourceName。
因此,有漏洞的反序列代码实现如下即可:
public class FastjsonTest {
public static void main(String[] argv){
testJdbcRowSetImpl();
}
public static void testJdbcRowSetImpl(){
//JDK 8u121以后版本需要设置改系统变量
System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");
//RMI
String payload2 = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"rmi://localhost:1099/Exploit\"," +
" \"autoCommit\":true}";
JSONObject.parseObject(payload2);
}
}
漏洞复现的流程如下:
以下是参考的代码来源,fastjson 漏洞代码测试。(https://github.com/earayu/fastjson_jndi_poc)
如何解决 json 反序列化漏洞问题
- 可以升级版本,比如 fastjson 后面版本,增强 AutoType 打开时的安全性 fastjson,增加 AutoType 黑名单等等,都是为了应对这些安全漏洞。
- 反序列化有 fastjson、gson、jackson 等等类型,可以替换其他类型。
- 升级+打开 safemode。
3. XSS 攻击
3.1 什么是 XSS
★
XSS 攻击全称跨站脚本攻击(Cross-Site Scripting),这会与层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,因此有人将跨站脚本攻击缩写为 XSS。它指的是恶意攻击者往 Web 页面里插入恶意 html 代码,当用户浏览该页之时,嵌入其中 Web 里面的 html 代码会被执行,从而达到恶意攻击用户的特殊目的。XSS 攻击一般分三种类型:存储型、反射型、DOM 型 XSS。
”
3.2 XSS 是如何攻击的
拿反射型举个例子吧,流程图如下:
我们搞点简单代码样例吧,首先正常 html 页面如下:
<input type="text" name="name" />
<input type="submit" value="搜索" οnclick="http://127.0.0.1/search?name=">
</body>
- 用户输入搜索信息,点击搜索按钮,就是到达正常服务器的。如果黑客在 url 后面的参数中加入如下的恶意攻击代码:
http://127.0.0.1/search?keyword="<a href ="http://www.baidu.com"><script>alert('XSS');</script></a>
- 当用户打开带有恶意代码的 URL 的时候,正常服务器会解析出请求参数 name,得到"",拼接到 HTML 中返回给浏览器。
- 用户浏览器接收到响应后执行解析,其中的恶意代码也会被执行到。
4.这里的链接我写的是百度搜索页,实际上黑客攻击的时候,是引诱用户输入某些重要信息,然后跳到他们自己的服务器,以窃取用户提交的内容信息。
3.3 如何解决 XSS 攻击问题
- 不相信用户的输入,对输入进行过滤、过滤标签等,只允许合法值。
- HTML 转义。
- 对于链接跳转,如<a href="xxx" 等,要校验内容,禁止以 script 开头的非法链接。
- 限制输入长度等等。
4. CSRF 攻击
4.1 什么是 CSRF 攻击
CSRF,跨站请求伪造(英语:Cross-site request forgery),简单点说就是,攻击者盗用了你的身份,以你的名义发送恶意请求。跟跨网站脚本(XSS)相比,XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任。
4.2 CSRF 是如何攻击的
我们来看下这个例子(来自百度百科):
-
- Tom 登录银行,没有退出,浏览器包含了 Tom 在银行的身份认证信息。
- 黑客 Jerry 将伪造的转账请求,包含在帖子中。
- Tom 在银行网站保持登录的情况下,浏览帖子。
- 将伪造的转账请求连同身份认证信息,发送到银行网站。
- 银行网站看到身份认证信息,以为就是 Tom 的合法操作,最后造成 Tom 资金损失。
4.3 如何解决 CSRF 攻击
- 检查 Referer 字段。HTTP 头中有一个 Referer 字段,这个字段用以标明请求来源于哪个地址。
- 添加校验 token。
5. 文件上传下载漏洞
5.1 文件上传漏洞
★
文件上传漏洞是指用户上传了一个可执行的脚本文件,并通过此脚本文件获得了执行服务器端命令的能力。常见场景是 web 服务器允许用户上传图片或者普通文本文件保存,而用户绕过上传机制上传恶意代码并执行从而控制服务器。
”
解决办法一般就是:
- 限制服务器相关文件目录的权限。
- 校验上传的文件,如后缀名禁止上传恶意代码的文件。
- 尽量禁止使用前端上传的文件名。
5.2 文件下载漏洞
文件下载漏洞,举个例子,使用 .. 等字符,使应用读取到指定目录之外的其他目录中的文件内容,从而可能读取到服务器的其他相关重要信息。
6. 敏感数据泄露
这个相对比较好理解,一般敏感信息包括密码、用户手机身份证信息、财务数据等等,由于 web 应用或者 API 未加密或者疏忽保护,导致这些数据极易被黑客利用。所以我们需要保护好用户的隐私数据,比如用户密码加密保存,请求采用 https 加密,重要第三方接口采用加签验签,服务端日志不打印敏感数据等等。
7. XXE 漏洞
7.1 什么是 XXE
★
XXE 就是 XML 外部实体注入。当允许引用外部实体时,通过构造恶意内容,就可能导致任意文件读取、系统命令执行、内网端口探测、攻击内网网站等危害。
”
7.2 XXE 三种攻击场景
- 场景1. 攻击者尝试从服务端提取数据。
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ELEMENT foo (#ANY)>
<!ENTITY file SYSTEM "file:///etc/passwd">]>
]>
<foo>&xxe;</foo>
- 场景2. 攻击者通过将上面的实体行更改为以下内容来探测服务器的专用网络。
<!ENTITY xxe SYSTEM "https://192.168.1.1/private">]>
- 场景3. 攻击者通过恶意文件执行拒绝服务攻击。
<!ENTITY xxe SYSTEM "file:///dev/random">]>
7.3 如何防御 XXE
- 使用开发语言提供的禁用外部实体的方法。
- 过滤用户提交的 XML 数据,过滤 <!DOCTYPE和<!ENTITY 等关键词。
8. DDoS 攻击
8.1 什么是 DDos 攻击
DDoS 攻击,英文全称是 Distributed Denial of Service,谷歌翻译过来就是“分布式拒绝服务”。一般来说是指攻击者对目标网站在较短的时间内发起大量请求,大规模消耗目标网站的主机资源,让它无法正常服务。在线游戏、互联网金融等领域是 DDoS 攻击的高发行业。
为了方便理解,引用一下知乎上一个非常经典的例子:
★
我开了一家有五十个座位的重庆火锅店,由于用料上等,童叟无欺。平时门庭若市,生意特别红火,而对面二狗家的火锅店却无人问津。二狗为了对付我,想了一个办法,叫了五十个人来我的火锅店坐着却不点菜,让别的客人无法吃饭。
”
8.2 如何应对 DDoS 攻击
- 高防服务器,即能独立硬防御50Gbps以上的服务器,能够帮助网站拒绝服务攻击,定期扫描网络主节点等。
- 黑名单
- DDoS 清洗
- CDN 加速
9. 框架或应用漏洞
- Struts 框架漏洞:远程命令执行漏洞和开放重定向漏洞。
- QQ Browser 9.6:API 权限控制问题导致泄露隐私模式。
- Oracle GlassFish Server:REST CSRF。
- WebLogic: 未授权命令执行漏洞。
- Hacking Docker:Registry API 未授权访问。
- WordPress 4.7 / 4.7.1:REST API 内容注入漏洞。
10. 弱口令、证书有效性验证、内部接口在公网暴露、未鉴权等权限相关漏洞
10.1 弱口令
★
- 空口令
- 口令长度小于8
- 口令不应该为连续的某个字符(QQQQQQ)
- 账号密码相同(例:root:root)
- 口令与账号相反(例:root:toor)
- 口令纯数字(例:112312324234, 电话号)
- 口令纯字母(例:asdjfhask)
- 口令以数字代替字母(例:hello word, hell0 w0rd)
- 口令采用连续性组合(例:123456,abcdef,654321,fedcba)
- 服务/设备默认出厂口令
”
10.2 证书有效性验证漏洞
如果不对证书进行有效性验证,那 https 就如同虚设啦。
- 如果是客户生成的证书,需要跟系统可信根 CA 形成信任链,不能为了解决 ssl 证书报错的问题,选择在客户端代码中信任客户端中所有证书的方式。
- 证书快过期时,需要提前更换。
10.3 未鉴权等权限相关漏洞
一些比较重要的接口,一般建议鉴权。比如你查询某账号的转账记录,肯定需要先校验该账号是不是操作人的。