Java代码审计的第二章-跨站脚本

Java代码审计的第二章-跨站脚本

首先还是要思考一下几个问题

1.什么是Xss

2.如何在代码中找到他们

3.如何防护

那么带着这几大疑问,我们正式开始今天的探究

Xss的中文名称为跨站脚本攻击,为了和层叠样式表(Cascading StyleSheets,CSS)的缩写进行区分,故将跨站脚本攻击的英文缩写为XSS。XSS是一种在Web应用中常见的安全漏洞,它允许用户将恶意脚本植入到Web页面中,当其他用户访问此页面时,植入的恶意脚本就会在其他用户的客户端中执行。XSS漏洞的问题很多,可以通过XSS漏洞获取客户端用户的信息,比如用户登录的Cookie信息;可以通过XSS蠕虫进行传播;可以在客户端中植入木马;可以结合其他漏洞攻击服务器,在服务器中植入木马等, 一般来说,XSS的危害性没有SQL注入的大,但是一次有效的XSS攻击可以做很多事情,比如获取Cookie、获取用户的联系人列表、截屏、劫持等。根据服务器后端代码的不同,XSS的种类也不相同,一般可以分为反射型、存储型以及和反射型相近的DOM型。漏洞危害有:窃取Cookie,键盘记录,截屏,网页挂马,命令执行

总的来说,xss能干浏览器能干的所有事情,所以对于xss的防范,特别是存储型xss更是重中之重

那么我们如何发现他们

比如

输入
request.getParmeter(param) 

${param}

输出
 response.getWriter().print()

jsp中的 通过“request.getParameter”获取msg传入的值,然后通过“<%=msg%>”将其输出到网页中。

<%=变量%>

<%out.println%>

<%=%>

还有一种是 EL表达式

 例如:

“<%=request.getParameter("username")%>”等价于“${param.username}”

其中还有 <c:out>输出 , <c:if> if判断执行, <c:forEach> 迭代输出

在model类中则还有这些

  • - <c:forEach ModelAndView
    - ModelMap
    - Model
  •  

而在代码中,根据我们之前搭建的java代码学习审计台可以看的更清晰

// 简单的反射型XSS,没对输出做处理。当攻击者输入恶意js语句时可触发@GetMapping("/reflect")
public static String input(String content) {
    return content;
}
   

我们可以很直接的看到,对于输入content参数 没有任何校验直接进行了返回,被浏览器当成js代码执行

d2b5ca33bd20240419111757

d2b5ca33bd20240419111812

防范,除了比较直接的类型限制,还可以

// 将特殊字符做转义

private static String XssFilter(String content) {
    content = StringUtils.replace(content, "&", "&amp;");
    content = StringUtils.replace(content, "<", "&lt;");
    content = StringUtils.replace(content, ">", "&gt;");
    content = StringUtils.replace(content, "\", "&quot;");
    content = StringUtils.replace(content, "'", "'");
    content = StringUtils.replace(content, "/", "/");
    return content;
}                   

将所有能用到的字符进行转义,输出后,全都属于字符串类型

d2b5ca33bd20240419112136

d2b5ca33bd20240419112151

同时如果是spring 框架,同样会进行转义

// 采用Spring自带的方法会对特殊字符全转义

import org.springframework.web.util.HtmlUtils;

@GetMapping("/safe1")
public static String safe1(String content) {
    return HtmlUtils.htmlEscape(content);
}

对于富文本编辑器,可以这样修复

// 场景:针对富文本的处理方式,需保留部分标签

import org.jsoup.Jsoup;
import org.jsoup.safety.Whitelist;

public static String safe3(String content) {
    Whitelist whitelist = (new Whitelist())
           .addTags("p", "hr", "div", "img", "span", "textarea")  // 设置允许的标签
           .addAttributes("a", "href", "title")          // 设置标签允许的属性, 避免如nmouseover属性
           .addProtocols("img", "src", "http", "https")  // img的src属性只允许http和https开头
           .addProtocols("a", "href", "http", "https");
    return Jsoup.clean(content, whitelist);

还可以使用控件库ESAPI

// ESAPI 是一个免费、开源的、网页应用程序安全控件库,它使程序员能够更容易写出更低风险的程序
// 官网:https://owasp.org/www-project-enterprise-security-api/

public static String safe4(String content){
    return ESAPI.encoder().encodeForHTML(content);
}

还有其他一些存在漏洞的dome

1.经典的request.getParament

 public void Message(HttpServletRequest req, HttpServletResponse resp) {

 String message = req.getParameter("msg"); try {
 
 resp.getWriter().print(message);
 } catch (IOException e) {
 // TODO Auto-generated catch block e.printStackTrace();
 }
 }

2.存储型dome,输入直接存入数据库

public void ShowMessage(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
 // TODO Auto-generated method stub
 MessageInfoService msginfo = new MessageInfoServiceImpl();
 List<MessageInfo> msg = msginfo.MessageInfoShowService();
 if( msg != null){
 req.setAttribute("msg", msg);
 req.getRequestDispatcher("/message.jsp").forward(req, resp);
 return ;
 }
 }
其中,MessageInfoShowService 主要是⽤于实例化

调⽤MessageInfoShowDao()类,该类内容如下:
try {
 ....
 MessageInfoDaoImpl() ,然后调
String sql = "select * from message";
 ps = conns.prepareStatement(sql);
 rs = ps.executeQuery();
 messageinfo = new ArrayList<MessageInfo>();
 while(rs.next()){
 MessageInfo msg = new MessageInfo();
 msg.setName(rs.getString("name"));
 msg.setMail(rs.getString("mail"));
 msg.setMessage(rs.getString("message"));
 messageinfo.add(msg);
 }
 ....
 }
 }

主要执⾏的是从message 表中查询所有数据,然后将 name、mail、message 的值加到 messageinfo
 List 中,最后返回给 servlet 层。

数据来源可以从这里看出,这段代码中有地址转发,在message.jsp 中存在以下内容:
<%
 List<MessageInfo> msginfo =
(ArrayList<MessageInfo>)request.getAttribute("msg");
for(MessageInfo m:msginfo){
 %>
 <table>
 <tr><td class="klytd"> 留⾔⼈:</td>
 <td class ="hvttd"> <%=m.getName() %></td>
 </tr>
<tr><td class="klytd"> e-mail:</td><td class ="hvttd"> <%=m.getMail() %>
 </td>
 </tr>
 <tr><td class="klytd"> 内容:</td><td class ="hvttd"> <%=m.getMessage() %>
 </td></tr>
 </table> <% } %>
 </div>

而可以控制输入点的地方同样没有限制

这是两个比较常见的dome示例,真实环境可能会更加的复杂,所以要始终追着数据走,从输入到输出一步步校验

好了,今天的xss就说到这了,有什么不对的地方还请多多指教,笔者一定虚心请教并改正。

© 版权声明
THE END
喜欢就支持一下吧
点赞9 分享
评论 共4条

请登录后发表评论

    请登录后查看评论内容