【web防护】web安全框架及常见web攻击防护

ESAPI简介


Enterprise Security API,ESAPI (OWASP企业安全应用程序接口)是一个免费、开源的、网页应用程序安全控件库,它使程序员能够更容易写出更低风险的程序。ESAPI接口库被设计来使程序员能够更容易的在现有的程序中引入安全因素。ESAPI库也可以成为作为新程序开发的基础。
直接调用ESAPI的Java接口进行过滤的示例代码:
String output = ESAPI.encoder().encodeForHTML(input);
JSTL标签库调用ESAPI示例代码:
引入标签库
<%@ taglib prefix=”esapi” uri=”http://www.owasp.org/index.php/Category/OWASP_Enterprise_Security_API”%>
输出时调用:
${var}
四、Maven引入
com. .security qsecurity-esapisupport 0.0.3
五、防范SQL注入
在应用开发过程,所有开发人员必须严格按照本规范明确规定的方式进行数据操接口操作,以消除由于编码不规范导致的sql注入问题,任何数据库接口操作都禁止拼接字符串。
5.1 JAVA防SQL注入要求
公司所有JAVA开发的生产应用系统在开发过程中对数据库接口操作只能使用以下四种中的一种。
5.1.1 Java JDBC Prepare
默认情况下,要求使用预处理执行SQL语句,对所有传入SQL语句中的变量做绑定。这样用户拼接进来的变量,无论内容是什么都会被当做替代符号“?”所替代的值。数据库也不会把拼接进来的SQL代码数据,当做SQL语句的一部分去解析。
Java JDBC Prepare示例:
com.mysql.jdbc.Connection conn = db.JdbcConnection.getConn(); final String sql = “select * from product where pname like ?”; java.sql.PreparedStatement ps = (java.sql.PreparedStatement) conn.prepareStatement(sql); ps.setObject(1, “%”+request.getParameter(“pname”)+”%”); ResultSet rs = ps.executeQuery();
5.1.2 MyBatis
MyBatis使用时,SQL参数时统一使用#{},禁止使用${},
name = #{name} 针对like查询,在程序中对参数拼接%符号,并在SQL配置中使用#{}接收 针对order by和group by,使用枚举限定查询参数,并在SQL配置中使用foreach生成order by和group by参数,如: List> sorts = new LinkedList>(); sorts.add(new Sort(UserListQuery.ORDER.NAME, Direction.ASC)); sorts.add(new Sort(UserListQuery.ORDER.LAST_LOGIN_TIME, Direction.DESC)); UserListQuery listQuery = new UserListQuery(0, 10, sorts); ListResult result = listBLogic.execute(listQuery); order by #{item.name} #{item.direction}
5.1.3 JdbcTemplate
使用JdbcTemplate时,禁止拼接参数做为SQL。统一使用?作为参数占位符。如:
private static final String SQL_USER_SELECT = “select id, name, last_login_time from users where name=?”; public List getUser(String name) { if (StringUtils.isBlank(name)) { return null; } else { return jdbcTemplate.queryForList(SQL_USER_SELECT, new Object[]{name}, User.class); } }
5.1.4 ECon
ECon con = null; try{ con = ConMan.get(“atest”); List> data = con.queryMap(“select a,b,c from test”, new Object[]{1,”str”, new Date()}); … }finally{ Closer.close(con); }
5.2 PHP防注入
5.2.1 PHP Prepare
Mysql示例:(具体请参考http://www.php.net/manual/en/mysqli.prepare.php)
/if (mysqli_connect_errno()) { printf(“Connect failed: %s\n”, mysqli_connect_error()); exit(); } $city = “Amersfoort”; / create a prepared statement /if ($stmt = mysqli_prepare($link, “SELECT District FROM City WHERE Name=?”)) { / bind parameters for markers / mysqli_stmt_bind_param($stmt, “s”, $city); / execute query / mysqli_stmt_execute($stmt); / bind result variables / mysqli_stmt_bind_result($stmt, $district); / fetch value / mysqli_stmt_fetch($stmt); printf(“%s is in district %s\n”, $city, $district); / close statement / mysqli_stmt_close($stmt); } / close connection */ mysqli_close($link); ?>

PG示例:(具体请参考http://php.net/manual/en/function.pg-prepare.php)

注意: 当遇到无法使用prepareStatement预处理执行功能时,应优先考虑对变量类型进行类型判断或进行转义,并捕获异常。
PHP防注入跟据后端使用数据库类型选择使用mysql_real_escape_string() 或pg_escape_string()函数. 使用转义函数时必须捕获异常。

六、防范XSS攻击


公司所在线应用必须对输出到客户端的变量进行相应的编码转义,不允许直接输出到客户端,返回
• (‘Content-Type: application/javascript; charset=utf-8’);
• (‘Content-Type: text/javascript; charset=utf-8’);
• (‘Content-Type: application/json; charset=utf-8’);
的情况除外。
具体输出场景请参考下一小节。
6.1 在HTML标签和属性中输出时:
6.1.1 标签内输出示例: $var

$var
在HTML标签和属性中输出变量值时,所有标签中输出的变量,如果未做任何处理,都将导致XSS.在这种场景下,XSS的利用方式一般是构造一个

或者

解决方法:
JAVA:使用ESAPI.encoder().encodeForHTML() 或者
JSP:使用jstl标签库

等价于
),
使用jstl代替ESAPI.encoder().encodeForHTML() “>

PHP: 使用htmlspecialchars(string,ENT_QUOTES)
6.1.2 HTML属性位置输出示例:

XSS代码
“><” 解决方法: JAVA:使用ESAPI.encoder().encodeForHTMLAttribute() 或者 JSP: ${var} PHP: 使用Htmlspecialchars(string,ENT_QUOTES) 6.1.3 当变量值输出到


攻击者需要先闭合引号才能实施XSS攻击,攻击者输入的代码 “;alert( s1/);//”

解决方法:
JAVA:使用ESAPI.encoder().encodeForJavaScript()防御XSS
JSP:
${var}
PHP: 使用自定义JavascriptEncode()函数
function JavascriptEncode($str) { $out = array(); $out_sub = 0; for($i=0; $i标签中输出类似:
test
当攻击者输入’);alert( s/);// 的时候将构造出如下代码:
test
解决办法:
JAVA:使用, ESAPI.encoder().encodeForJavaScript()
JSP :
${var}
PHP :使用, 使用自定义JavascriptEncode()函数
6.1.5 在css中输出:

当$var变量的值被设置为javascript:alert(1)时,整段代码被构造成

解决方法:
JAVA: 使用ESAPI.encoder().encodeForCSS()
JSP :
${var}
PHP: 暂无

6.1.6 在URL位置输出:
当将变量输出在url位置的时候,应对值的内容进行urlencode输出编码。
我的订单
解决方法:
JAVA: 使用ESAPI.encoder().encodeForURL()
JSP :
${var}
PHP: 使用 urlencode()函数
6.1.7 DOM Based XSS


当变量内容是从动态语言取值输出到

七、防止csrf攻击(使用ESAPI生成token)


线上应用涉及到重要操作请求(用户的增、删、改以及敏感信息)的需要考虑防CSRF攻击的防御 ,以下是使用ESAPI防止CSRF攻击的原理:
生成csrf token并放置到cookie或session中
String csrfToken=ESAPI.randomizer().getRandomString(32,EncoderConstants.CHAR_ALPHANUMERICS ); Cookie token= new Cookie(“csrfToken”,csrfToken); token.setMaxAge(2724*3600); //csrftoken的有效期应与用户验证的cookie变量完全相等,如用户中心的q,v等cookie变量response.addCookie(token);
在用户操作页面将该csrfToken的值做为表单中隐藏input元素的value
out.println(“”);
当用户提交操作请求时在后端检验cookie中的csrfTonke值是否与input提交的csrfToken完全相等,如果相等才允许执行操作。
Cookie cookies[] = request.getCookies(); String csrfToken = “”; for (Cookie cookie:cookies){ if(cookie.getName().equals(“csrfToken”)){ csrfToken= cookie.getValue(); } } String hideToken = request.getParameter(“csrfToken”); if(hideToken.equals(csrfToken)){ out.println(“修改成功”); }else{ out.println(“非法请求”); }
对于get型的增、删、改操作,将csrfToken放置到请求的url中,使用cookie中的csrfToken与url查询参数中的csrfToken进行对比。

发表评论

电子邮件地址不会被公开。 必填项已用*标注