代码安全

admin 2022年4月6日10:31:48评论45 views字数 6487阅读21分37秒阅读模式

        随着互联网深入到各行各业,越来越多的应用系统、网站等被人类通过网络连接、访问。如何保障系统、网站不会因黑客的恶意攻击而导致系统崩溃、数据泄露等安全问题,解决此问题的最根本的手段还是要回归到代码上面,只有写出的代码是安全的、是无懈可击的、没有任何逻辑漏洞,才能杜绝一切安全问题。本文从以下几个方面讲述系统漏洞产生的原理及如何预防这些漏洞,做到代码安全。内容比较浅显,不做深入阐释。


sql注入

    什么是sql注入呢?下面以一个通俗的例子来理解。

    一个正常的sql语句:

Select password from user where username=’admin


     在实际实现中(以Java为例):

String username = request.getParameter(“username”);String sql = “select password from user where username=’”+username+”’”;

    当通过表单向后端传入username参数值为admin时,sql就变成上面所示的语句,sql执行就得到admin用户对于的password。如果,用户恶意输入 username参数为:

‘ and 1=2 union select123456      (mysql数据库)或者and 1=2 union select123456from dual where1’=’1      (oracle数据库)

    那么sql语句就变成:

Select password from user where username =’’ and 1=2 union select123456’;或者Select password from user where username =’’ and 1=2 union select123456from dual where1’=’1’;

    执行sql,得到结果总是123456。


    这种将sql指令输入到原来的sql指令中执行的方式,就是所谓的sql注入攻击。攻击者通过精心构造输入参数,可以在相当大的范围内以当前用户的权限读写数据库。


    由上面可知,sql注入攻击根本原因是拼接sql语句。

    因此,sql注入漏洞防范的最好的方法是使用参数化查询。

String sqlcmd = "select Password from CMS_SYS_USERS where Username = ?";    PreparedStatement stmt =con.prepareStatement(sqlcmd);stmt.setString(1, request.getParameter("UserName"));

    在参数化查询中,数据库在读取参数前首先完成对SQL语句的编译。不论输入的参数如何、内容转义与否,都不会作为SQL代码(而是二进制数据)来执行SQL语句。


XSS攻击

XSS就是跨站脚本攻击(Cross Site Scripting),是为了不和层叠样式表(Cascading Style Sheets,CSS)的缩写混淆。XSS漏洞形成原理:

一段正常的JSP代码:

<span><%=title%></span>

    将变量title显示在页面上。这种做法本身是功能需要,合情合理但是如果参数title的内容是由恶意用户控制的:

<script>恶意JS代码</script>

    页面内容就会变成:

<span><script>恶意JS代码</script></span>

    加载该页面的用户就会在浏览器上执行这段JS代码。

    总之就是:XSS漏洞的根本原因是构造动态文档时,未进行正确的编码或转义。   

    如何防范XSS攻击呢?对输出数据使用HtmlEncoder对一些字符做转义处理,所有HTML和XML中输出的数据,都应该做html escape转义:

代码安全

<span><%=ESAPI.encoder().EncoderForHTML("<script>alert(document.cookie)</script>","HTML")%></span>                                      <span>&lt;script&gt;alert(document.cookie)&lt;/script&gt;</span>


CSRF攻击

    CSRF就是跨站请求伪造攻击(Cross-Site Request Forgery),是一种劫持被攻击者浏览器发送HTTP请求到目标网站触发某种操作的漏洞。在原理上是一种与XSS相左的攻击方式,其最终的作用对象是服务器上的WEB程序,是远端的,而XSS的最终作用对象是浏览器,是本地的。攻击者在用户浏览网页时,利用页面元素(例如img的src),强迫受害者的浏览器向Web应用程序发送一个改变用户信息的请求。由于发生CSRF攻击后,攻击者是强迫用户向服务器发送请求,所以会造成用户信息被迫修改,更严重者引发蠕虫攻击。


    CSRF攻击可以从站内和站外发起:

    1. 从站内发起CSRF攻击,需要利用网站本身的业务,比如“自定义头像”功能,恶意用户指定自己的头像URL是一个修改用户信息的链接,当其他已登录用户浏览恶意用户头像时,会自动向这个链接发送修改信息请求。站内CSRF攻击通常结合XSS一同使用,如下例子,恶意攻击者在某一论坛,在留言板中输入如下内容:

<form name="form1" method="post" action="http://10.81.10.201/cms/admin/user.action.php"> <input name="act" value="add">     <input name="username" value="hacker">     <input name="password" value="hacker">     <input name="password2" value="hacker">     <input name="userid" value="0"></form><script language="javascript">document.form1.submit();</script>

    当系统管理员登录系统并查看留言时,就会在管理员完全没有察觉的情况下,执行了恶意攻击者的JS语句去创建用户名和密码都为hacker的用户。这样恶意攻击者就通过伪造请求的方式创建了hacker这个用户。

    2. 从站外发送请求,则需要恶意用户在自己的服务器上,放一个自动提交修改个人信息的htm页面,并把页面地址发给受害者用户,受害者用户打开时,会发起一个请求。如果恶意用户能够知道网站管理后台某项功能的URL,就可以直接攻击管理员,强迫管理员执行恶意用户定义的操作。站外攻击实例如下:

    1)在页面中加入一个<img>标签,浏览器就会发送一个请求,以获取其src属性引用的值

    2)攻击者将敏感操作的URI作为src

    3)继承Cookie,以浏览者的身份作敏感访问并操作

    4)危害:在用户无意识情况下进行危险操作

    攻击者为了攻击某站点的登录用户,可以构造2个HTML页面。首先在页面a.htm中写一个没有面积的iframe,以免受害者看到提交结果而产生警觉:

<iframe src="b.htm" width="0" height="0"></frame>


    然后在页面b.htm中,写入CSRF攻击代码:

<form id="modify" action="http://xx.com/servlet/modify" method="POST"><input name="email"><input name="userid"></form><script>document.getElementById("modify").submit();</script>

    接下来,攻击者需要设法诱骗合法用户访问a.htm,一旦用户打开a.htm,就会自动提交表单,从而达到CSRF攻击的目的。


    如何防范CSRF攻击呢?


    判断该请求是否为网站内已知正常的功能页面,查看http请求头部的referer字段,referer总是指向请求的来源,若来源是正常或已知的网站,那么就不存在CSRF攻击。但是这个方法并不是绝对的,referer是可以被伪造的。另外,这种方式对于站内攻击也是无效的。对于csrf攻击最有效的手段就是使用不可猜测的字段。如下:

代码安全

    攻击者无法预测其他用户的随机TOKEN值,所以无法构造跨站链接或表单。类似的,图形验证码、短信验证码、UKey、要求再次输入密码等方式均对CSRF有效。


SSRF攻击

    SSRF就是服务端请求伪造(Server-Side Request Forgery)攻击,即服务端的网络访问能够被攻击者操纵所导致的安全漏洞。例如下面代码:

代码安全

    攻击者若提供一个恶意的url,那么服务器端就会出现异常。因此,SSRF往往意味着僵尸网络,恶意代理,甚至跳板入侵内网。


任意文件上传和任意文件下载

    任意文件上传,即服务器端没有对用户上传的文件类型做校验或者校验不完整,导致用户可以上传恶意文件到服务器。如下面代码:

String filePath = getServletContext().getRealPath("/") + "GoodsImages";File file = new File(filePath);String saveName = UUID.randomUUID().toString() + ".";if (!file.exists()){file.mkdir();}SmartUpload su = new SmartUpload();su.initialize(getServletConfig(), request, response); su.upload();saveName = saveName + su.getFiles().getFile(0).getFileExt();String fileName = filePath + "/" + saveName;if (su.getFiles().getFile(0).isMissing()){out.print("<script>alert('请选择上传的图片!'),window.location='GoodsAdd.jsp'</script>");return;}su.getFiles().getFile(0).saveAs(fileName);

    上传图片时,没有限制上传文件的类型,此时上传的是一个jsp文件,如果jsp中含有恶意代码,那么系统很有可能受到攻击。因此,在上传文件时,一定要判断文件的类型,是否合法。判断文件类型要通过文件的魔数(Java中有相应方法),而不是简单的截取文件后缀名。

    任意文件下载漏洞形成的原因:在日常开发中,常见这样的文件下载功能:

String filename = request.getParameter("file");    String absolutePath = WEB_PATH + "/" + filename;WebUtils.downFile(absolutePath);

    提交的文件路径没有进行过滤,就与其它目录路径进行字符串拼接。此种情况下,利用../来遍历目录,就可以下载任意文件。在特定情况下,攻击者即使不使用“..”来遍历目录,也能够下载到一些敏感文件:

String filename = request.getParameter("/WEB-INF/web.xml");

    虽然和任意文件上传的名字上很接近,但限制文件后缀名的方法在任意文件下载漏洞中行不通:

String filename = request.getParameter("file");    if(!filename.endsWith(".jpg")&&!filename.endsWith(".bmp"){        throw new SecturityException("只允许下载jpg或bmp文件");    }    String absolutePath = WEB_PATH + "/" + filename;    WebUtils.downFile(absolutePath);    此时使用类型这样的Payload:    xx.jsp?file=..%2F..%2F..%2Fetc%2Fpasswd%00%.bmp

    在多数C/C++程序(比如操作系统)中,字符%00被认为是字符串的结束(而非忽略该字符)。在访问文件时,空字符可以截断字符串,从而绕过下载文件类型限制。

任意文件下载漏洞防范措施就是:尽量避免由用户干涉文件访问的路径,而是在服务端直接确定文件路径。


应用服务器安全性优化

    曾经参与了一款保密产品的申请工作,其中应用服务器的安全性是保密局对产品的要求之一,下面以tomcat为例,如何使其安全性达到要求:


    1. 修改server.xml文件中的<Server port="8005" shutdown="SHUTDOWN">。从安全的角度上考虑,我们需要把这个shutdown指令改成一个别人不容易猜测的字符串,可以同时把端口也改了。否则telnet到服务器的8005端口,输入“SHUTDOWN”,然后回车,服务器会关闭。

    2. 处理好tomcat的管理安全。删除webapps文件夹下的manager、host-manager和admin文件夹。将conf文件夹下的tomcat-users.xml中所有用户信息配置注释掉。

    3. 运行错误网页。如果找不到网页即出现404错误,会显示服务器版本号,服务器配置也一目了然。避免这一现象,配置404页面。在web.xml文件中倒数第二行,添加以下内容:

<error-page>    <error-code>404</error-code>   <location>/404.jsp</location>  </error-page>  <error-page>    <error-code>500</error-code>    <location>/500.jsp</location>    </error-page>


    4. 关闭8009端口。8009端口是tomcat和apache的mod_proxy_ajp,mod_jk沟通的端口,用不到就关闭它,将server.xml文件中的这段代码注释掉:

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443"/>

    5. 关闭war自动部署。Tomcat默认是开启war自动部署的,为了防止被植入木马等恶意程序,要关闭自动部署功能,修改server.xml文件中的这段代码:<Host appBase="webapps" autoDeploy="false" name="localhost" unpackWARs="true">,将autoDeploy属性值修改为false。

    6. 禁止列出目录。如果设置不当,就会列出Web当前目录中的所有文件,然而在Tomcat也不例外。如果浏览者可以在客户端浏览Web目录,那将会存在较大的安全隐患,因此我们要确认Tomcat的设置中禁止列目录。修改confweb.xml下的:

<init-param><param-name>listings</param-name><param-value>false</param-value></init-param>

    7.开启安全日志功能,安全日志保存到logs文件夹中,安全日志默认是开启的,检查一下是否存在这个tomcat_home/logs文件夹。

原文链接:https://blog.csdn.net/yangyuge1987/article/details/81302770


学习更多技术,关注我们:

原文始发于微信公众号(编码安全研究):代码安全

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年4月6日10:31:48
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   代码安全http://cn-sec.com/archives/649652.html

发表评论

匿名网友 填写信息