2026/4/18 5:58:08
网站建设
项目流程
中端网站建设公司,宁波seo在线优化公司,wordpress文章图片显示大图,科技公司网站系统文章目录 前言代码审计的思路常见漏洞的代码审计1. HTTP响应头截断修复方案#xff1a;2. 硬编码问题3. SQL注入4. maven不安全模块5. 服务端请求伪造#xff08;SSRF#xff09;6. 路径遍历7. 命令注入 常见代码审计工具#xff0c;代码审计为什么不能只用工具#xff1f…文章目录前言代码审计的思路常见漏洞的代码审计1. HTTP响应头截断修复方案2. 硬编码问题3. SQL注入4. maven不安全模块5. 服务端请求伪造SSRF6. 路径遍历7. 命令注入常见代码审计工具代码审计为什么不能只用工具代码审计工具代码审计工具优缺点优点缺点前言这篇文章主要是总结一下在安全工作中常见漏洞的代码审计方法以及修复方案希望能对初学代码审计小伙伴们有所帮助。这是我给粉丝盆友们整理的代码审计的基础教程喜欢的朋友们记得给我点赞支持和收藏一下关注我学习黑客技术。代码审计的思路1. 懂得漏洞类型产生原理2. 懂得危险函数的参数不当使用可造成的漏洞威胁。例如涉及到命令执行代码执行的evalassertarray\_mapusort等 本身函数的脆弱性is\_numericmd5等。3. 晓得php函数的脆弱性。例如与并不是强大无比不可绕过的也要结合代码设计逻辑。4. php的技巧。5. php版本及配置不当结合函数不当利用造成的漏洞威胁。常见漏洞的代码审计1. HTTP响应头截断漏洞描述HTTP响应截断是由于应用程序未对用户提交的数据进行严格过滤当用户恶意提交包含 CR回车即URL编码%0d或\r和 LF换行符即URL编码%0a或\n的HTTP请求服务器可能会创建两个 HTTP 响应攻击者可以控制第二个响应并加载攻击。攻击者可控制响应的内容构造XSS攻击其中响应中包含恶意的JavaScript或其它代码在用户的浏览器中执行也有可能让用户重定向到攻击者控制的Web内容或在用户的主机上执行恶意操作。审计方法检查对响应头字段是否进行安全处理。如果未对响应头进行任何安全处理则为确认//未对响应头做任何安全处理审计时为确认 String data; if (data ! null){ response.addHeader(Location, /author.jsp?lang data); }再举一例//同样的未对响应头做任何安全处理审计时为确认 String author request.getParameter(AUTHOR_PARAMETER); // ... Cookie cookie new Cookie(author, author); response.addCookie(cookie);如果对响应头做了响应的安全处理则为误报//使用Refenence类对环境变量值进行编码剔除特殊字符为误报 if (data ! null){ String decode Reference.decode(data); response.addHeader(Location, /author.jsp?lang decode); }修复方案1、对用户的输入进行合理验证对特殊字符如、、’、”等等进行编码。2、创建一份安全字符白名单只接受完全由这些受认可的字符组成的输入出现在 HTTP 响应头文件中。3、使用源代码静态分析工具进行自动化的检测可以有效的发现源代码中的 HTTP 响应截断问题。2. 硬编码问题漏洞描述硬编码问题是指将敏感数据包括口令和加密密钥部分账号的密码以及其他敏感信息等硬编码在程序中。审计步骤1、看扫描出的硬编码是否为常规单词或通读代码查看是否有硬编码敏感文件2、如果是常规单词则为误报如//fipAddress为硬编码 public class IPaddress { private String ipAddress 172.16.254.1; public static void main(String[] args) { //... } }可以使用 javap -c IPaddress 命令来反编译 class 来发现其中硬编码的服务器 IP 地址此处反编译器的输出信息可以直接透漏服务器的明文 IP 地址为172.16.254.1再举一例//SECRET_PASSWORD为硬编码 private String SECRET_PASSWORD No fear in my heart!; Properties props new Properties(); props.put(Context.SECURITY_CREDENTIALS, password);3、如果是随机字符串则为确认或待确认如//1546272000000为硬编码 byte[] sr hBaseClient.buildRowKey(devId, 1546272000000);再举一例//qafgshw1900wxxxx为硬编码 private String accessKeyId qafgshw1900wxxxx;4、追踪key值如果key为硬编码则为确认如//key值为硬编码 byte[] key {1, 2, 3, 4, 5, 6, 7, 8}; SecretKeySpec spec new SecretKeySpec(key, AES); Cipher aes Cipher.getInstance(AES); aes.init(Cipher.ENCRYPT_MODE, spec); return aesCipher.doFinal(secretData);追踪key值如果追踪不到或者为安全形式则为误报如//无法再继续追踪key值为误报 public static byte[] encryptByPrivateKey(byte[] data, String key) throws Exception { //key为密钥 byte[] keyBytes decryptBASE64(key); PKCS8EncodedKeySpec pkcs8KeySpec new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory KeyFactory.getInstance(KEY_ALGORITHM); Key privateKey keyFactory.generatePrivate(pkcs8KeySpec); Cipher cipher Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, privateKey); return cipher.doFinal(data); }再来一栗//存储密钥。KeyStore.getInstance(PKCS12)为密钥库为误报 try{ KeyStore keyStore KeyStore.getInstance(PKCS12); keyStore.load(null, null); KeyGenerator keyGen KeyGenerator.getInstance(AES); keyGen.init(128); Key key keyGen.generateKey(); keyStore.setKeyEntry(secret, key, password.toCharArray(), null); keyStore.store(new FileOutputStream(output.p12), password.toCharArray()); } catch (Exception ex){ ex.printStackTrace(); }修复方案推荐使用配置文件或者通过配置中心来下发这些敏感配置密码和密钥应存储在单独的加密配置文件或密钥库中。3. SQL注入漏洞描述注入攻击的本质是程序把用户输入的数据当做代码执行。这里有两个关键条件第一是用户能够控制输入第二是用户输入的数据被拼接到要执行的代码中从而被执行。sql 注入漏洞则是程序将用户输入数据拼接到了 sql 语句中从而攻击者即可构造、改变 sql 语义从而进行攻击。漏洞举例(1) 直接通过拼接 sqlRequestMapping(/SqlInjection/{id}) public ModelAndView SqlInjectTest(PathVariable String id){ String mysqldriver com.mysql.jdbc.Driver; String mysqlurl jdbc:mysql://127.0.0.1:3306/test?userrootpassword123456useUnicodetruec haracterEncodingutf8autoReconnecttrue;#直接通过拼接 sql String sql select * from user where id id; ModelAndView mav new ModelAndView(test2); try{ Class.forName(mysqldriver); Connection conn DriverManager.getConnection(mysqlurl); PreparedStatement pstt conn.prepareStatement(sql); ResultSet rs pstt.executeQuery();再来一例//没有做任何其他安全处理措施 stmt conn.createStatement(); rs stmt.executeQuery(select * from user where username username and passwordpassword);(2) 预编译使用有误漏洞举例//只使用了占位符 RequestMapping(/SqlInjection/{id}) public ModelAndView SqlInjectTest(PathVariable String id){ String mysqldriver com.mysql.jdbc.Driver; String mysqlurl jdbc:mysql://127.0.0.1:3306/test?userrootpassword123456useUnicodetruec haracterEncodingutf8autoReconnecttrue; String sql select * from user where id ?; ModelAndView mav new ModelAndView(test2); try{ Class.forName(mysqldriver); Connection conn DriverManager.getConnection(mysqlurl); PreparedStatement pstt conn.prepareStatement(sql); //pstt.setObject(1, id); //一般使用有误的是没有用这一句编码者以为在上面的sql语句中直 接使用占位符就可以了。 ResultSet rs pstt.executeQuery();审计步骤查看预编译的完整性关键函数定位 setObject()、setInt()、setString()、setSQLXML()关联上下文搜索 set* 开头的函数。(3) %和_oracle 中模糊查询问题RequestMapping(/SqlInjection/{id}) public ModelAndView SqlInjectTest(PathVariable String id){ String mysqldriver com.mysql.jdbc.Driver; String mysqlurl jdbc:mysql://127.0.0.1:3306/test?userrootpassword123456useUnicodetruec haracterEncodingutf8autoReconnecttrue; String sql select * from user where id ?; ModelAndView mav new ModelAndView(test2); try{ Class.forName(mysqldriver); Connection conn DriverManager.getConnection(mysqlurl); PreparedStatement pstt conn.prepareStatement(sql); pstt.setObject(1, id); //使用预编译 ResultSet rs pstt.executeQuery();审计步骤定位相关 sql 语句上下文查看是否有显式过滤机制。修复方案上面的代码片段即使这样依然存在 sql 注入原因是没有手动过滤%。预编译是不能处理这个符号的以需要手动过滤否则会造成慢查询造成 dos。(4) order by 问题String sql “Select * from news where title ?” “order by ‘” time “’asc”审计步骤定位相关 sql 语句上下文查看是否有显式过滤机制。修复方案类似上面的这种 sql 语句 order by 后面是不能用预编译处理的只能通过拼接处理所以需要手动过滤。(5) 有关$符号的情况#{}相当于jdbc中的preparedstatement传入的字符串需要赋值后使用可以有效防止sql注入KaTeX parse error: Expected ‘EOF’, got ‘#’ at position 44: …法防止sql注入 简单的说就是#̲{}传过来的参数带单引号’…{}传过来的参数不带单引号。但是orderby是动态SQL只能用KaTeX parse error: Expected ‘EOF’, got ‘#’ at position 5: {}用#̲{}会多个’ 导致sql语句…{}。//需要转义的字符串仍使用$ delete from ${tableName}修复方案对于可以使用#{}的情况直接使用#{}即可解决问题对于不能使用#{}的情况如orderby需要增加额外的过滤逻辑以此判断输入内容是否正常如字段类型、字段长度等4. maven不安全模块漏洞描述Maven是一个Java开发比较常用的项目管理工具可以对Java项目进行构建、依赖管理。当它配置一个不安全的模块时即存在安全风险。审计方法查看配置的版本是否属于安全版本区间。如果是则确认//3.9版本是存在漏洞的版本。安全版本是3.11以上 dependency groupIdcom.hazelcast/groupId artifactIdhazelcast-client/artifactId version3.9/version /dependency修复方案配置为安全版本即可同时应注意解决兼容性问题5. 服务端请求伪造SSRF漏洞描述SSRF是攻击者让服务端发起指定的请求攻击的目标一般是从外网无法访问的内网系统。SSRF形成的原因大都是由于代码中提供了从其他服务器应用获取数据的功能但没有对目标地址做过滤与限制。比如从指定URL链接获取图片、下载等。一般利用http协议来探测端口利用file协议读取任意文件。利用场景SSRF漏洞一般位于远程图片加载与下载、图片或文章收藏功能、URL分享、通过URL在线翻译、转码等功能点处。关键词/接口/类包// Java HttpURLConnection.getInputStream URLConnection.getInputStream Request.Get.execute Request.Post.execute URL.openStream ImageIO.read OkHttpClient.newCall.execute HttpClients.execute HttpClient.execute审计方法1、内网系统的SSRF直接为误报内网系统之间互调互传2、检查请求的URL是否为外部可控即由外部传入3、检查请求的返回是否对请求的返回数据做了安全处理漏洞示例//请求URL为外部可控返回数据直接展示 String url request.getParameter(picurl); StringBuffer response new StringBuffer(); URL pic new URL(url); HttpURLConnection con (HttpURLConnection) pic.openConnection(); con.setRequestMethod(GET); con.setRequestProperty(User-Agent, Mozilla/5.0); //发起请求触发漏洞 BufferedReader in new BufferedReader(new InputStreamReader(con.getInputStream())); String inputLine; while ((inputLine in.readLine()) ! null) { response.append(inputLine); } in.close(); modelMap.put(resp,response.toString()); return getimg.htm;再举一例//HttpClients函数的SSRF漏洞代码审计时为确认 String url request.getParameter(url); CloseableHttpClient client HttpClients.createDefault(); HttpGet httpGet new HttpGet(url); HttpResponse httpResponse client.execute(httpGet); //发起请求修复方案使用白名单校验HTTP请求url地址避免请求url外部可控避免将请求响应及错误信息返回给用户禁用不需要的协议及限制请求端口仅仅允许http和https请求等6. 路径遍历目录/路径遍历、任意文件上传/下载漏洞描述在下载文件相关的代码中若不对HTTP请求中的待下载文件名进行检查则有可能产生任意文件下载漏洞。攻击者可以指定文件名、文件路径等文件操作的参数越权访问正常情况下无法到达的系统资源。审计方法判断是否存在上传下载行为判断路径是否可被外部控制如果外部可控则向下判断是否对文件路径做了安全措施如果做了安全措施为误报漏洞示例没有对路径做任何安全处理如//没有对路径做任何安全处理措施 path config/path; File file new File(path); System.out.println(path); response.setHeader(Content-Disposition, attachment;filename\\ new String(path.getBytes(), ISO8859-1) \\); response.setContentLength((int) file.length()); byte[] buffer new byte[4096];// 缓冲区 BufferedOutputStream output null; BufferedInputStream input null;再举一例//对下载的文件未做安全处理 public Response getImage(javax.ws.rs.PathParam(image) String image) { File file new File(resources/images/, image); if (!file.exists()) { return Response.status(Status.NOT_FOUND).build(); } return Response.ok().entity(new FileInputStream(file)).build(); }修复方案使用getCanonicalPath()、getAbsolutePath()等方法获取规范路径对文件操作参数进行输入验证过滤特殊字符通过文件头判断来限制文件类型而不是通过文件后缀来判断服务器安全配置策略文件。将所能读取的文件限定在特定的目录下7. 命令注入漏洞描述命令注入是指通过提交恶意构造的参数破坏命令语句结构当对用户输入的命令没有进行限制或者过滤不严导致用户可以执行任意命令时就会造成命令执行漏洞。通常表现为攻击者能够篡改程序执行的命令或命令执行的环境从而直接或间接的控制了所执行的命令。常见的命令执行方法// Java Runtime.exec ProcessBuilder.start GroovyShell.evaluate审计方法检查是否是系统命令如果不是系统命令而是常规字符串拼接则为误报检查所执行的命令是否为外部可控制如果外部不可控例如命令拼接参数不为外部控制则为误报外部可控制的情况下检查命令的拼接参数是否做了安全措施如果未做安全措施即为确认漏洞示例(1) 没有对外部传入的命令拼接参数做任何安全处理措施如//没有对外部传入的命令参数command做任何安全处理 System.out.println(Command: ping command); Runtime rt Runtime.getRuntime(); Process proc rt.exec(cmd.exe /C ping command); int res proc.waitFor(); if(res !0){ System.out.println(process error: res); } InputStream in (res 0)? proc.getInputStream() : proc.getErrorStream(); BufferedReader readernew BufferedReader(new InputStreamReader(in)); buffernew StringBuffer(); String line; while((line reader.readLine())!null){ buffer.append(line\\n); }再举一例//同样没有对外部传入的命令拼接参数input做任何安全处理 Runtime r Runtime.getRuntime(); r.exec(/bin/sh -c some_tool input);(2) 对外部传入的命令拼接参数做安全限制如//对外部传入的命令拼接参数做了限制 //正则限定为合法IP地址 if (!Pattern.matches(([1-9]|[1-9]\\\\d|1\\\\d{2}|2[0-4]\\\\d|25[0-5])(\\\\.(\\\\d|[1-9]\\\\d|1\\\\d{2}|2[0-4]\\\\d|25[0-5])){3}, command)){ //如果不是IP则匹配不成功则为F!F则为TT则执行此代码块 result.put(message, Error!); return DataUtil.toJson(result); } System.out.println(Command: ping command); Runtime rt Runtime.getRuntime(); Process proc rt.exec(cmd.exe /C ping command); int res proc.waitFor(); if(res !0){ System.out.println(process error: res); } InputStream in (res 0)? proc.getInputStream() : proc.getErrorStream(); BufferedReader readernew BufferedReader(new InputStreamReader(in)); buffernew StringBuffer(); String line; while((line reader.readLine())!null){ buffer.append(line\\n); }修复方案构建白名单只允许其中的字符出现在输入中应有应用程序来控制命令并使用绝对路径来执行命令严格的权限限制程序执行外部命令使用最小权限原则严格的参数校验常见代码审计工具代码审计为什么不能只用工具代码审计是一种发现程序漏洞安全分析为目标的程序源码分析方式。今天主要分享的是几款常用的代码审计工具以及代码审计工具有哪些优缺点代码审计工具seay代码审计工具是一款开源的利用C#开发的一款代码审计工具。主要有SQL注入、xss跨站、命令执行、文件包含、文件上传、正则匹配、数据库执行监控等程序漏洞的监测。frotify sca是惠普开发的一款商业性质的代码审计工具主要包含了数据流、控制流、语义、配置、结构五大分析引擎。rips是一款php开发监测php程序漏洞的代码分析工具。该工具现目前的版本是0.5并很早之前就已经停止更新。该工具能够发现SQL注入、xss跨站文件包含文件上传、代码执行、文件读取等漏洞。findbugs是一款静态分析工具属于eclipse的插件工具。burp suite属于一款工具集成平台主要包含了proxy(拦截http/s的代理服务器)、Spider(只能感应的网络爬虫)、Scannerweb应用漏洞、Intruder高度可配置工具、Repeater应用响应工具、Sequencer预测一些不可预知的漏洞补发单独的http请求、Decoder程序的解码、Comparer反映请求和响应的差异。该工具需要安装java环境。Gerrit是一个基于 Web 的代码审查系统适于采用 Git 版本控制系统开发的项目进行在线代码审查。Phabricator是一个完整的开源软件应用程序以Web基础代码审查、计划、测试、浏览与审计评分、发现Bug等功能。Review Assistant是Visual Studio的代码审查插件。可以创建审阅请求并在不离开Visual Studio的情况下对其进行响应。支持TFSSubversionGitMercurial和Perforce。cobra支持PHP、Jav等主要开发语言及其它数十种文件类型支持检测多种漏洞类型支持命令行模式和API模式。VCG它是一个基于字典的自动化源代码扫描工具支持 C, C#, VB, PHP, Java, PL/SQL and COBOL等多种语言可以由用户自定义需要扫描的数据可以对源代码中所有可能存在风险的函数和文本做一个快速定位和检索。RIPSPHP代码审计工具支持跨平台部署小巧强大。SonarQubeSonarQube 是一款用于代码质量管理的开源工具它主要用于管理源代码的质量。通过插件形式可以支持众多计算机语言比如 java, C#, goC/C, PL/SQL, Cobol, JavaScrip, Groovy 等。sonar可以通过PMD,CheckStyle,Findbugs等代码规则检测工具来检测代码帮助发现代码漏洞。代码审计工具优缺点优点1.降低人工成本对于应用程序扫描模式是通用的计算机比人类更擅长这类扫描。在这种情况下扫描器在扫描大型代码库漏洞时扮演着重要角色2.发现漏洞的所有实例扫描器可以非常有效地识别特定漏洞的所有实例及具体位置。跟踪大型代码库中所有文件的缺陷很难扫描器对于这种情况很有帮助3.源库分析一些分析器通过源库分析的方式跟踪代码并识别漏洞。分析器识别可能的应用输入并在所有源代码中彻底追踪输入直到发现所有不符合安全代码模式的应用输入。源库分析能够帮助开发人员更好地理解代码缺陷和获得代码缺陷的根本原因4.详细的报告格式扫描器能够提供详细的分析报告包括具体代码段的漏洞、漏洞的风险等级和详细描述。缺点1.未涉及业务逻辑缺陷扫描器不能识别应用程序的业务逻辑、事务处理和敏感数据。通常扫描器不能发现应用程序中需要实现的特定于某些功能和设计的安全控制。这些被认为是静态代码分析器的最大限制2.范围有限通常静态代码分析器被设计用于特定的框架或语言并且能够在一定范围内搜索特定漏洞模式的集合。在此范围之外静态代码分析器并不能解决在搜索模式库中未涵盖的问题3.不能发现设计缺陷代码框架的设计缺陷没有固定模式静态代码扫描器专注于代码层面。需要人工查看代码才能识别设计问题4.误报被扫描器标记的问题并非完全真实需要有经验、了解安全编码的技术人员理解问题缺陷并对其进行分类。网络安全学习资源分享:给大家分享一份全套的网络安全学习资料给那些想学习 网络安全的小伙伴们一点帮助对于从来没有接触过网络安全的同学我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线大家跟着这个大的方向学习准没问题。因篇幅有限仅展示部分资料朋友们如果有需要全套《网络安全入门进阶学习资源包》请看下方扫描即可前往获取