Java代码审计漏洞-XSS漏洞
Java代码审计漏洞-XSS漏洞
基础知识
https://www.cnblogs.com/-meditation-/p/16168961.html
个人学习笔记,直接看代码,不写奇怪的东西,分析代码写注释。
情况一:反射型XSS
//1.
/**
* Vuln Code.
* ReflectXSS
* http://localhost:8080/xss/reflect?xss=<script>alert(1)</script>
*
* @param xss unescape string
*/
@RequestMapping("/reflect")
@ResponseBody
public static String reflect(String xss) {
return xss;
}
/**
客户端传入xss参数,服务端获取值后直接返回
*/
//2.
@WebServlet("/demo")
public class xssServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");// 设置响应类型
String content = request.getParameter("content"); //获取content传参数据
request.setAttribute("content", content); //content共享到request域
request.getRequestDispatcher("/WEB-INF/pages/xss.jsp").forward(request, response); //转发到xxs.jsp页面中
}
}
//xss.jsp代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
${requestScope.content}
</head>
<body>
</body>
</html>
/**
和上面的情况一样,但是中间加了共享到request域,转发到目标页面,EL表达式获取直接输出
*/
情况二:存储型XSS
//1.
/**
* Vul Code.
* StoredXSS Step1
* http://localhost:8080/xss/stored/store?xss=<script>alert(1)</script>
*
* @param xss unescape string
*/
@RequestMapping("/stored/store")
@ResponseBody
public String store(String xss, HttpServletResponse response) {
Cookie cookie = new Cookie("xss", xss);
response.addCookie(cookie);
return "Set param into cookie";
}
/**
客户端传入xss参数,服务端获取值后传入cookie的XSS键返回给客户端
*/
/**
* Vul Code.
* StoredXSS Step2
* http://localhost:8080/xss/stored/show
*
* @param xss unescape string
*/
@RequestMapping("/stored/show")
@ResponseBody
public String show(@CookieValue("xss") String xss) {
return xss;
}
/**
前面已经将XSS写入Cookie,同一浏览器访问http://localhost:8080/xss/stored/show,服务端获取Cookie中XSS的值并返回客户端
*/
//2.
//输入点
public void StoreXss(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO Auto-generated method stub
String name = req.getParameter("name");
String mail = req.getParameter("mail");
String message = req.getParameter("message");
if(!name.equals(null) && !mail.equals(null) && !message.equals(null)){
MessageInfoService msginfo = new MessageInfoServiceImpl();
msginfo.MessageInfoStoreService(name, mail, message);
resp.getWriter().flush();
resp.getWriter().close();
}
}
//控制器
public void ShowMessage(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
MessageInfoService msginfo = new MessageInfoServiceImpl();
//MessageInfoShowService主要是用于实例化MessageInfoDaoImpl()
List<MessageInfo> msg = msginfo.MessageInfoShowService();
if( msg != null){
req.setAttribute("msg", msg);
req.getRequestDispatcher("/message.jsp").forward(req, resp);
return ;
}
}
//MessageInfoShowService()
try {
....
//主要执行的是从message表中查询所有数据,然后将 name、mail、message 的值加到 messageinfo List 中,最后返回给 servlet 层。
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);
}
....
return messageinfo;
}
}
/**
return messageinfo; 把查询的name、mail、message 的值返回给List<MessageInfo> msg
req.getRequestDispatcher("/message.jsp").forward(req, resp); 转发到 message.jsp
*/
<%
//直接获取msg输出
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>
安全代码
//1.定义转义输入字符函数
/**
* safe Code.
* http://localhost:8080/xss/safe
*/
@RequestMapping("/safe")
@ResponseBody
public static String safe(String xss) {
return encode(xss);
}
private static String encode(String origin) {
origin = StringUtils.replace(origin, "&", "&");
origin = StringUtils.replace(origin, "<", "<");
origin = StringUtils.replace(origin, ">", ">");
origin = StringUtils.replace(origin, "\"", """);
origin = StringUtils.replace(origin, "'", "'");
origin = StringUtils.replace(origin, "/", "/");
return origin;
}
//2.全局过滤器过滤
<filter>
<filter-name>XssSafe</filter-name>
<filter-class>XssFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>XssSafe</filter-name>
<url-pattern>/\*</url-pattern> //格式问题加了个转移字符 ‘/*’
</filter-mapping>
//过滤器的内容
//XssFilter实现:
public class XssFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
chain.doFilter(new XssHttpServletRequestWrapper((HttpServletRequest) request), response);
}
}
//XssHttpServletRequestWrapper实现
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
public XssHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
}
@SuppressWarnings("rawtypes")
public Map<String,String[]> getParameterMap(){
Map<String,String[]> request_map = super.getParameterMap();
Iterator iterator = request_map.entrySet().iterator();
while(iterator.hasNext()){
Map.Entry me = (Map.Entry)iterator.next();
String[] values = (String[])me.getValue();
for(int i = 0 ; i < values.length ; i++){
values[i] = xssClean(values[i]);
}
}
return request_map;
}
public String[] getParameterValues(String paramString)
{
String[] arrayOfString1 = super.getParameterValues(paramString);
if (arrayOfString1 == null)
return null;
int i = arrayOfString1.length;
String[] arrayOfString2 = new String[i];
for (int j = 0; j < i; j++){
arrayOfString2[j] = xssClean(arrayOfString1[j]);
}
return arrayOfString2;
}
public String getParameter(String paramString)
{
String str = super.getParameter(paramString);
if (str == null)
return null;
return xssClean(str);
}
public String getHeader(String paramString)
{
String str = super.getHeader(paramString);
if (str == null)
return null;
str = str.replaceAll("\r|\n", "");
return xssClean(str);
}
private String xssClean(String value) {
//ClassLoaderUtils.getResourceAsStream("classpath:antisamy-slashdot.xml", XssHttpServletRequestWrapper.class)
if (value != null) {
// NOTE: It's highly recommended to use the ESAPI library and
// uncomment the following line to
// avoid encoded attacks.
// value = encoder.canonicalize(value);
value = value.replaceAll("\0", "");
// Avoid anything between script tags
Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>",
Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid anything in a src='...' type of expression
scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
| Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid anything in a href='...' type of expression
scriptPattern = Pattern.compile("href[\r\n]*=[\r\n]*\\\"(.*?)\\\"",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
| Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Remove any lonesome </script> tag
scriptPattern = Pattern.compile("</script>",
Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
// Remove any lonesome <script ...> tag
scriptPattern = Pattern.compile("<script(.*?)>",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
| Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid eval(...) expressions
scriptPattern = Pattern.compile("eval\\((.*?)\\)",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
| Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid expression(...) expressions
scriptPattern = Pattern.compile("expression\\((.*?)\\)",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
| Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid javascript:... expressions
scriptPattern = Pattern.compile("javascript:",
Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid vbscript:... expressions
scriptPattern = Pattern.compile("vbscript:",
Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid onload= expressions
scriptPattern = Pattern.compile("onload(.*?)=",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
| Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
}
return value;
}
}
//3.使用工具类xssProtect
/**
这是谷歌提供的一个用于过滤来自用户输入字段的XSS攻击的Java库
项目中需要引入 xssProtect-0.1.jar、antlr-3.0.1.jar、antlr-runtime-3.0.1.jar等3个 jar 包
*/
protectedAgainstXSS(String html){StringReader reader = new StringReader(html); StringWriter writer = new StringWriter();
try {
// 从“ html”变量解析传入的字符串
HTMLParser.process( reader, writer, new XSSFilter(), true );
// 返回经过解析和处理的字符串
return writer.toString();
} catch (HandlingException e) {
}
}
//具体的使用方式可以参考:https://www.iteye.com/blog/liuzidong-1744023
找XSS的方法:
1.扫描器直接扫描,再去回溯
2.拿到一个项目主要是去看看,这个项目有没有一些过滤之类的组件。
假设没有找到类似的过滤组件,则去随机找几个点去看看是不是存在XSS,
参考文章
https://github.com/JoyChou93/java-sec-code/blob/master/README_zh.md
本文来自博客园,作者:九天揽月丶,转载请注明原文链接:https://www.cnblogs.com/-meditation-/articles/16160999.html