十大漏洞:SQL注入、跨站脚本、失效的访问控制、失效的身份认真和会话、安全配置错误、敏感信息泄露、攻击检测与防范不足、跨站请求伪造、使用含有已知漏洞的组件、未受保护的APIs。在系统架构设计、技术选型和编码阶段就需要充分考虑安全性要求,避免各类Web应用安全漏洞。
SQL注入
1、原理
SQL注入即是指web应用程序对用户输入数据的合法性没有判断,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。它不是利用操作系统的BUG来实现攻击,而是利用程序员编程时的疏忽。
例如,一般用户登录用的SQL语句为:SELECT * FROM user WHERE username='admin' AND password='passwd',此处admin和passwd分别为用户输入的用户名和密码,如果程序员没有对用户输入的用户名和密码做处理,就可以构造万能密码成功绕过登录验证,如用户输入' or 1#,SQL语句将变为:SELECT * FROM user WHERE username='' or 1#' AND password='','' or 1为TRUE,#注释掉后面的内容,所以查询语句可以正确执行。
另外,通过or或者and 与1=1、1=2等组合即可判断是否存在SQL注入的漏洞,例如:
http://xxxxxxxx?id=xxx AND 1=1 --
http://xxxxxxxx?id=xxx AND 1=2 --
如果前一个能返回正常信息而后一个不能,则可以判定会有id注入的可能。因为后者即使id正常,1=2永远无法成立。一反一正说明注入的语句可能会正常运行。
2、危害
- 绕过登录或者获取到系统管理员权限
- 注入时如果数据库权限设置不当,可能会查看到数据库系统表、数据,甚至可以非法增删改查数据等
- 如果权限设置不当,注入木马或者利用存储过程扩展功能操作操作系统的shell,比如master.dbo.xp_cmdshell,从而控制整个服务器
- 注入过程如果错误没有正确处理,则可能暴露整个系统文件夹结构
3、防范方法
- 所有的查询语句都使用数据库提供的参数化查询接口,参数化的语句使用参数而不是将用户输入变量嵌入到SQL语句中。当前几乎所有的数据库系统都提供了参数化SQL语句执行接口,使用此接口可以非常有效的防止SQL注入攻击。
- 对进入数据库的特殊字符(’”<>&*;等)进行转义处理,或编码转换。
- 确认每种数据的类型,比如数字型的数据就必须是数字,数据库中的存储字段必须对应为int型。
- 数据长度应该严格规定,能在一定程度上防止比较长的SQL注入语句无法正确执行。
- 网站每个数据层的编码统一,建议全部使用UTF-8编码,上下层编码不一致有可能导致一些过滤模型被绕过。
- 严格限制网站用户的数据库的操作权限,给此用户提供仅仅能够满足其工作的权限,从而最大限度的减少注入攻击对数据库的危害。
- 避免网站显示SQL错误信息,比如类型错误、字段不匹配等,防止攻击者利用这些错误信息进行一些判断。
- 在网站发布之前建议使用一些专业的SQL注入检测工具进行检测,及时修补这些SQL注入漏洞。
具体在软件开发层面,表现在以下:
- 前端表单进行参数格式控制;
- 后台进行参数格式化,过滤所有涉及sql的非法字符;可通过拦截器统一拦截
//过滤 sql注解、关键字、符号等
static String reg = "(?:')|(?:--)|(/\\*(?:.|[\\n\\r])*?\\*/)|"+ "(\\b(select|update|and|or|delete|insert|trancate|char|into|substr|ascii|declare|exec|count|master|into|drop|execute)\\b)";
static Pattern sqlPattern = Pattern.compile(reg, Pattern.CASE_INSENSITIVE);//表示忽略大小写
/***************************************************************************
* 参数校验@param str ep: "or 1=1"
*/
public static boolean isSqlValid(String str) {
Matcher matcher = sqlPattern.matcher(str);
if (matcher.find()) {
System.out.println("参数存在非法字符,请确认:"+matcher.group());//获取非法字符:or
return false;
}
return true;
}
- 持久层使用参数化的持久化sql,使用预编译语句集,切忌使用拼接字符串;例如spring的jdbcTemplate防止sql注入,mybatis防止sql注入,jpa防止sql注入。
String sql= "select * from user where name=?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, name);
ResultSet rs = ps.executeQuery();