3.1 SQL注入
当应用程序将用户输入的内容,拼接到SQL语句中,一起提交给数据库执行时,就会产生SQL注入威胁
1、是否存在全局过滤器
过滤器配置、过滤函数等
2、过滤器是否可以过滤所有查询请求
3、请求是否都按要求经过过滤器处理
4、过滤器的过滤是否符合要求
5、初期检查可以依据PHPIDS的规则库,后期根据收集的情况予以补充
6、是否使用了预编译
7、预查询是指在将数据传入SQL语句前明确指定传输数据的类型,以执行必要的转换。在Java中预查询的调用方式为prepareStatement。
8、是否存在SQL语句拼接
某些特殊的查询(特别复杂的组合查询)难免用到SQL语句拼接,遇到这种情况,就需要检查拼接是否有可能导致注入。
代码示例:
String query = "SELECT account_balance FROM user_data WHERE user_name = "+ request.getParameter("customerName");
try {
Statement statement = connection.createStatement( … );
ResultSet results = statement.executeQuery( query );
}
//以上代码中由于使用了拼接方式构造sql语句,所以存在sql注入漏洞
3.2 跨站攻击
是否存在全局XSS过滤器(论坛的过滤库)
是否存在需过滤和不需过滤两种输出,页面是否控制恰当(*)
某些情况下可能存在两种输出,文本输出和富文本(HTML)输出,要强制文本输出,只需要调用HTMLEncode()对内容进行编码后输出即可;但是富文本本身就需要使用html来进行格式的控制,简单的编码就无法使用,这时需要在此类内容从客户端输入(用户提交)或输出给客户端(显示)时进行危险代码过滤。
输出的时候是否进行编码(HTML、JS)
3.3 csrf防护
Web 表单是否使用了Token(或验证码)
代码示例:
<form action="http://spdb.com/modify.jsp" method="POST">
<input name="email">
<input name="tel">
<input name="realname">
<input name="userid">
<input type="submit">
</form>
//因为表单中没有token,以上代码中存在csrf漏洞
Web表单提交(成功或不成功)后token(或验证码)是否重置。原理同图形验证码的校验原理。
检查Token的生成算法是否安全。
检查服务器获取Web表单参数值的方式。
如果在操作时不严格区分GET和POST,在没有Token(或验证码)的辅助下很容易导致CSRF的发生。
3.4 文件上传漏洞
是否限制了上传文件的扩展名
以白名单形式指定允许上传的扩展名;以黑名单形式指定禁止上传的文件扩展名
是否对上传文件进行了重命名操作
重命名操作是否安全,防止重命名过程中产生二次风险
是否对上传文件的存放位置禁止了脚本执行
代码示例:
protected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String contentType = request.getContentType();
int ind = contentType.indexOf("boundary=");
String boundary = contentType.substring(ind+9);
String pLine = new String();
String uploadLocation = new String(UPLOAD_DIRECTORY_STRING);
//判断contentType是否是multipart/form-data
if (contentType != null && contentType.indexOf("multipart/form-data") != -1)
{
//从HttpHeader中提取文件名
BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream()));
...
pLine = br.readLine();
String filename = pLine.substring(pLine.lastIndexOf("\\"),pLine.lastIndexOf("\""));
...
//把文件输出到上传目录
try {
BufferedWriter bw = new BufferedWriter(new FileWriter(uploadLocation+filename, true));
for (String line; (line=br.readLine())!=null; ) {
if (line.indexOf(boundary) == -1) {
bw.write(line);
bw.newLine();
bw.flush();
}
} //循环结束
bw.close();
}
catch (IOException ex) {...}
//输出成功加载并返回的HTML页面
}
//输出成功加载并返回的HTML页面
else
{...}
}
3.5 文件下载防护
是否存在客户端指定文件名的下载功能。
直接指定文件名的下载是否允许客户端指定路径。
对于不同用户的文件在下载时是否进行了权限控制。
文件下载功能中是否对用户的权限进行了检查。
代码示例:
protected void doPost(HttpServletRequest request,HttpServletResponse response)throws ServletException, IOException
{
try {
byte data[] = new byte[1];
//取得用户提交的图片文件名,没有检测是否为图片,也没有检测是否包含../../目录跳转的字符
String imgName = request.getParameter("imgName");
String imgKey = MD5Encrypt.MD5(imgName); //本地
if (imageCache.containsKey(imgKey)) {
data = (byte[]) imageCache.get(imgKey);
} else {
String imagePath = Consts.IMG_LOCAL_PAHT + imgName;
//没有对该参数进行严格的验证和过滤,就拼接成完整的图片路径
InputStream inputStream = null;
File imageFile = new File(imagePath);
logger.debug(imagePath + " " + imageFile.exists());
if (imageFile.exists() && imageFile.isFile()) {
inputStream = new FileInputStream(imagePath);
int i = inputStream.available();
data = new byte[i];
inputStream.read(data);
inputStream.close();
imageCache.put(imgKey, data);
} else {
……
}
}
//将文件内容输出到客户端
response.setContentType("image/*");
OutputStream outputStream = response.getOutputStream();
outputStream.write(data);
outputStream.close();
}
}
3.6 重定向与转发
是否具有客户端控制的重定向或转发
是否定义了重定向的信任域名或主机列表
是否对客户端的重定向或转发请求进行检查
代码示例:
public class RedirectServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException
{
String query = request.getQueryString();
if (query.contains("url")) {
String url = request.getParameter("url");
response.sendRedirect(url);
}
}
}
//服务端从客户端接收参数url,直接指定其为重定向地址