概述
接上一篇文章《网络信息系统安全检测方案设计(上)》。
HTTP 响应头拆分 CRLF 检测
CRLF 代表回车 (CR, ASCII 13, r) 以及换行 (LF, ASCII 10, n),也就是”回车 + 换行”(rn)的意思。许多网络协议,包括 HTTP 同样沿用 CRLF 来表示每一行的结束。HTTP 头 header 的定义便是基于这样的"Key: Value"的结构,例如 "Location:"头用来表示重定向的URL地址,"Set-Cookie:"头用来设置 cookies。
CRLF 原理分析
HTTP 头用 CRLF 命令表示一行的结尾,这就意味着用户可以通过 CRLF 注入自定义 HTTP header。例如正常的 302 跳转是这样:
HTTP/1.1 302 Moved Temporarily
Date: Fri, 27 Jun 2014 17:52:17 GMT
Content-Type: text/html
Content-Length: 154
Connection: close
Location: http://www.qq.com
但是我们注入了一个换行,此时的返回就会变成这样:
HTTP/1.1 302 Moved Temporarily
Date: Fri, 27 Jun 2014 17:52:17 GMT
Content-Type: text/html
Content-Length: 154
Connection: close
Location: http://www.qq.com
Set-cookie: JSPSESSID=abc
这个时候这样我们就给访问者设置了一个 Session,造成一个“会话固定漏洞”。
CRLF 检测与防御
通过过滤 Response 的响应头和 Cookie 可以检测与防范大部分的 CRLF 注入。仍然是在 HttpServletResponseWrapper 中重写相关的方法。
@Override
public void addCookie(Cookie cookie) {
if (length + cookie.getValue().length() > MAX_COOKIE_SIZE)
return;
if (!isInWhiteList(cookie))
throw new RuntimeException("cookie:" + cookie.getName() + " is not in whitelist,not valid.");
try {
super.addCookie(CLRF.checkCookie(cookie));
length += cookie.getValue().length();
} catch (SecurityException e) {
e.printStackTrace();
}
}
@Override
public void setDateHeader(String name, long date) {
super.setDateHeader(CLRF.filterCLRF(name), date);
}
@Override
public void setIntHeader(String name, int value) {
super.setIntHeader(CLRF.filterCLRF(name), value);
}
@Override
public void addHeader(String name, String value) {
super.addHeader(CLRF.filterCLRF(name), XSS.xssFilter(CLRF.filterCLRF(value), null));
}
@Override
public void setHeader(String name, String value) {
super.setHeader(CLRF.filterCLRF(name), XSS.xssFilter(CLRF.filterCLRF(value), null));
}
上述的过滤方法如下,均是静态方法。
/**
* 如果 cookie 名称包含 CLRF 则抛出异常;接着过滤 cookie 内容
* @param inputCookie
* @return
* @throws SecurityException
*/
public static Cookie checkCookie(Cookie inputCookie) throws SecurityException {
if (inputCookie == null)
return null;
String name = inputCookie.getName(), value = inputCookie.getValue();
if (CLRF.containCLRF(name))
throw new SecurityException(" cookie 名称不能包含 CLRF,该 cookie 是:" + name);
String newValue = CLRF.filterCLRF(value);// 已经过滤好的 Cookie value
// 重新创建 cookie
Cookie newCookie = new Cookie(name, newValue);
newCookie.setComment(inputCookie.getComment());
if (inputCookie.getDomain() != null)
newCookie.setDomain(inputCookie.getDomain());
newCookie.setHttpOnly(inputCookie.isHttpOnly());
newCookie.setMaxAge(inputCookie.getMaxAge());
newCookie.setPath(inputCookie.getPath());
newCookie.setSecure(inputCookie.getSecure());
newCookie.setVersion(inputCookie.getVersion());
return newCookie;
}
/**
* 过滤
r 、n之类的换行符
* @param value
* @return
*/
public static String filterCLRF(String value) {
if (value == null || value.isEmpty())
return value;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < value.length(); i++) {
if (!(value.charAt(i) == 'r' || value.charAt(i) == 'n'))
sb.append(value.charAt(i));
}
return sb.toString();
}
/**
* 是否包含 r 、n之类的换行符
* @param name
* @return
*/
public static boolean containCLRF(String name) {
if (name == null || name.isEmpty())
return false;
for (int i = 0; i < name.length(); i++) {
if (name.charAt(i) == 'r' || name.charAt(i) == 'n')
return true;
}
return false;
}
SQL 注入攻击
SQL 注入攻击是常见的攻击方式。所谓 SQL 注入式攻击,就是攻击者把 SQL 命令插入到 Web 表单的输入域或页面请求的查询字符串,欺骗服务器执行恶意的 SQL 命令。在某些表单中,用户输入的内容直接用来构造(或者影响)动态 SQL 命令,或作为存储过程的输入参数,这类表单特别容易受到 SQL 注入式攻击。
SQL 注入原理分析
假设我们可以通过 http://localhost/test/userinfo.php?username=plhwin 这个 URL 来访问到具体某个会员的详情,正常情况下,如果浏览器里传入的 username 是合法的,那么 SQL 语句会执行:
SELECT uid,username FROM user WHERE username='plhwin'
但是,如果用户在浏览器里把传入的 username 参数变为 plhwin';SHOW TABLES-- hack,也就是当 URL 变为 http://localhost/test/userinfo.php?username=plhwin';SHOW TABLES-- hack 的时候,此时我们程序实际执行的 SQL 语句变成了:
SELECT uid,username FROM user WHERE username='plhwin';SHOW TABLES
SQL 注入检测与防御
防止 SQL 注入有多种方法,这里介绍“使用预编译语句”和过滤器的方法。Java 中使用 PrearedStatement 的 SQL 语句如下:
String sqlString ="INSERT INTO user(id, password, name, email, address) VALUES(?, ?, ?, ?, ?)";
PreparedStatement pstmt = connection.PreparedStatement(sqlString);
pstmt.setString(1, user.id);
pstmt.setString(2, user.password);
pstmt.setString(3, user.name);
pstmt.setString(4, user.email);
pstmt.setString(5, user.address);
使用占位符?代替参数,将参数与 SQL 语句分离出来,阻止了 SQL 注入。
过滤器的方法原理也十分简单,主要是通过正则匹配敏感字符串进行过滤。代码如下。
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
public class AntiSqlInjectionfilter implements Filter {
public void destroy() {
// TODO Auto-generated method stub
}
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
public void doFilter(ServletRequest args0, ServletResponse args1,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req=(HttpServletRequest)args0;
HttpServletRequest res=(HttpServletRequest)args1;
//获得所有请求参数名
Enumeration params = req.getParameterNames();
String sql = "";
while (params.hasMoreElements()) {
//得到参数名
String name = params.nextElement().toString();
//System.out.println("name===========================" + name + "--");
//得到参数对应值
String[] value = req.getParameterValues(name);
for (int i = 0; i < value.length; i++) {
sql = sql + value[i];
}
}
//System.out.println("============================SQL"+sql);
//有sql关键字,跳转到error.html
if (sqlValidate(sql)) {
throw new IOException("您发送请求中的参数中含有非法字符");
//String ip = req.getRemoteAddr();
} else {
chain.doFilter(args0,args1);
}
}
//效验
protected static boolean sqlValidate(String str) {
str = str.toLowerCase();//统一转为小写
String badStr = "'|and|exec|execute|insert|select|delete|update|count|drop|*|%|chr|mid|master|truncate|" +
"char|declare|sitename|net user|xp_cmdshell|;|or|-|+|,|like'|and|exec|execute|insert|create|drop|" +
"table|from|grant|use|group_concat|column_name|" +
"information_schema.columns|table_schema|union|where|select|delete|update|order|by|count|*|" +
"chr|mid|master|truncate|char|declare|or|;|-|--|+|,|like|//|/|%|#";//过滤掉的sql关键字,可以手动添加
String[] badStrs = badStr.split("\|");
for (int i = 0; i < badStrs.length; i++) {
if (str.indexOf(badStrs[i]) >= 0) {
return true;
}
}
return false;
}
}
在 web.xml 文件中的配置过滤器:
<filter>
<filter-name>antiSqlInjection</filter-name>
<filter-class>com.abc.AntiSqlInjectionfilter</filter-class>
</filter>
<filter-mapping>
<filter-name>antiSqlInjection</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
结束语
本文通过相对简单的手段检测了 XSS 攻击、CSRF 攻击、CRLF 注入和 SQL 注入攻击,用户只需要配置 Servlet 过滤器即可。由于考虑的地方可能不是太周全,加上水平有限,希望可以提出指正。最后
以上就是和谐万宝路为你收集整理的网络信息系统安全检测方案设计(下)的全部内容,希望文章能够帮你解决网络信息系统安全检测方案设计(下)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复