文章目录:

一:前言

1.定义

2.为什么要执行代码审计

3.审计流程

例子1:SQL注入漏洞审计

例子2:跨站脚本攻击(XSS)漏洞审计

例子3:文件包含漏洞审计

例子4:不安全的反序列化

4.审计方法

5.审计工具

5.1 Java代码审计的工具推荐

5.2 PHP代码审计的工具推荐

6.最佳实践

7.注意事项

8.代码审计的常用思路

二:扩展

1.Java

1.1 概念 

1.2 漏洞关键字

2.PHP

2.1 概念 

2.2 漏洞关键字 

三:举例

1.Java Web SQL注入漏洞

2.PHP SQL注入漏洞

3.Java SQL注入漏洞


一:前言

1.定义

简而言之:熟悉开发语言开发框架+经验+发现分析问题+修复 

代码审计是一种源代码分析技术,旨在发现程序中的错误、安全漏洞和违反程序规范的问题
    它通过对应用程序或系统的源代码进行逐条检查和分析,从规范性、安全性和可靠性等方面进行全面评估
    目的是及时发现并修复潜在的安全漏洞,减少系统被攻击的风险,提升整体网络安全水平

哪些地方需要用到代码审计

1.即将上线的新系统平台

2.存在大量用户访问、高可用、高并发请求的网站

3.存在用户资料等敏感机密信息的企业平台

4.互联网金融类存在业务逻辑问题的企业平台

5.开发过程中对重要业务功能需要进行局部安全测试的平台

2.为什么要执行代码审计

发现潜在的安全漏洞:
    代码审计能够对软件系统中的源代码进行全面、深入的检查和分析,从而发现其中可能存在的安全漏洞,如SQL注入、跨站脚本攻击(XSS)、文件包含漏洞等
    这些漏洞如果不被发现和修复,可能会被黑客利用,导致数据泄露、系统被入侵等严重后果


先于黑客发现系统的安全隐患:
    通过代码审计,企业可以先于黑客发现系统的安全隐患,并提前部署好安全防御措施
    这有助于确保系统在未知环境下也能经得起黑客的挑战,从而降低被攻击的风


发现代码中的错误和不足:
    代码审计不仅关注安全性,还能发现代码中的逻辑错误、性能瓶颈等问题
    这些问题如果不被及时修复,可能会影响软件的正常运行和用户体验


提升代码的可读性和可维护性:
    通过代码审计,可以检查代码是否符合编程规范和最佳实践
    规范的代码结构有助于提高代码的可读性和可维护性,从而降低后期维护的成本和风险


遵循信息安全法律法规:
    随着信息安全法、数据保护法等相关法律法规的出台,企业在开发和使用软件时需要遵循这些法律法规的要求
    代码审计报告可以为企业提供合规性支持,确保软件系统的开发和使用符合法律法规的规定


满足行业合规要求:
    在一些高度监管的行业,如金融行业、医疗健康等,代码审计是满足合规要求的重要步骤
    通过代码审计,可以确保软件系统符合行业标准和最佳实践,从而降低因违规操作而带来的法律风险


保障企业数据的安全:
    企业数据是企业的重要资产之一
    通过代码审计,可以及时发现并修复数据泄露的风险点,从而保障企业数据的安全性和完整性


提升用户信任度:
    对于面向公众的软件应用,通过第三方认证的代码审计报告可以显著提升用户对产品的信任度和满意度
    这有助于提升企业的品牌形象和市场竞争力


更新审计工具和技术:
    随着技术的不断发展,代码审计工具和技术也在不断更新和升级
    通过执行代码审计,企业可以及时了解并掌握最新的审计工具和技术,从而不断提升审计效率和质量


加强与开发团队的沟通和协作:
    代码审计需要开发人员、安全研究人员和测试人员等多方面的协作
    通过执行代码审计,可以加强团队成员之间的沟通和协作,共同提升软件系统的安全性和质量

3.审计流程

确定审计目标策略:明确审计的目的和范围,确定需要审计的代码和系统

部署环境:不同编程语言环境不同

信息收集:收集被审计的的源代码、配置文件、数据库结构等相关信息

执行审计:根据收集的信息,执行审计活动,包括代码审查、漏洞扫描和安全策略检查等
	静态分析:使用静态代码分析工具(对源代码进行扫描,发现潜在的编码问题和安全漏洞
	动态分析:通过运行应用程序,使用动态分析工具监控其行为,发现运行时错误和异常
	人工手动审查:对关键代码段进行手动审查,特别是那些处理用户输入、数据库查询、文件操作等敏感操作的代码
	业务逻辑分析:根据应用程序的业务逻辑,分析并验证其功能的正确性和安全性
	安全配置检查:检查应用程序的安全配置,如防火墙规则、数据库权限、会话管理等

分析结果:对审计结果进行分析和评估,确定问题的严重程度和影响范围

提供修复建议:针对发现的问题,提供修复建议和解决方案

跟踪和报告:跟踪问题的修复情况,并及时向相关人员报告审计结果

例子1:SQL注入漏洞审计

背景:某Web应用程序使用PHP开发,用户输入的数据直接用于构建SQL查询语句

审计过程:
    代码审查:审计人员检查PHP代码,发现用户输入的数据没有经过适当的过滤和验证,而是直接拼接到SQL查询语句中
    漏洞确认:通过构造恶意输入,如' OR '1'='1,成功绕过了应用程序的验证机制,并导致SQL查询返回了意外的结果
    风险评估:此漏洞可能导致攻击者能够访问、修改或删除数据库中的敏感数据

修复建议:
    使用参数化查询或预编译语句来构建SQL查询
    对用户输入的数据进行严格的过滤和验证

例子2:跨站脚本攻击(XSS)漏洞审计

背景:某Web应用程序允许用户在页面上发布评论,这些评论没有经过适当的过滤和编码,就直接显示在页面上

审计过程:
    代码审查:审计人员发现用户提交的评论内容直接插入到HTML页面中,没有进行适当的编码处理
    漏洞确认:通过提交包含恶意JavaScript代码的评论,成功地在其他用户的浏览器中执行了这段代码
    风险评估:此漏洞可能导致攻击者能够窃取用户的敏感信息、进行会话劫持或执行其他恶意操作

修复建议:
    对用户输入的数据进行HTML编码,以防止恶意代码的执行
    使用内容安全策略(CSP)来限制页面可以加载的资源类型

例子3:文件包含漏洞审计

背景:某Web应用程序允许用户通过URL参数指定要包含的文件名,这些文件名没有经过适当的验证

审计过程:
    代码审查:审计人员发现应用程序使用include或require语句来包含用户指定的文件,而没有对文件名进行验证
    漏洞确认:通过构造恶意URL参数,如?file=../../../../etc/passwd,成功包含了系统敏感文件的内容
    风险评估:此漏洞可能导致攻击者能够访问服务器的文件系统、读取敏感配置文件或执行任意代码

修复建议:
    对用户指定的文件名进行严格的验证和过滤
    使用白名单来限制可以包含的文件类型或目录
    禁用不必要的文件包含功能

例子4:不安全的反序列化

背景:某Web应用程序使用PHP的unserialize函数来处理用户输入的数据

审计过程:
    代码审查:审计人员发现应用程序没有对用户输入的数据进行适当的验证和过滤,而是直接将其传递给unserialize函数
    漏洞确认:通过构造恶意序列化数据,成功利用了unserialize函数中的漏洞,执行了任意代码
    风险评估:此漏洞可能导致攻击者能够远程执行任意代码、访问服务器资源或执行其他恶意操作

修复建议:
    避免使用unserialize函数来处理用户输入的数据
    如果必须使用unserialize函数,请确保对用户输入的数据进行严格的验证和过滤
    使用更安全的序列化/反序列化替代方案

4.审计方法

代码审查:由具备丰富经验的行业人员通过阅读开发文档和逐条检查分析源代码,找出可能存在的安全漏洞和风险
         这包括语法错误、逻辑错误、输入验证不足等问题


漏洞扫描:利用专业的漏洞扫描工具对代码进行扫描,找出其中可能存在的安全漏洞
         这包括缓冲区溢出、SQL注入、跨站脚本攻击等常见漏洞类型


安全策略检查:检查代码中的安全策略是否正确实施,如访问控制、数据加密等
         确保代码符合最佳安全实践和标准

5.审计工具

静态代码分析工具:如Fortify 、Snyk、SonarQube等,它们可以在不运行代码的情况下分析源代码,发现潜在的安全漏洞和代码质量问题


动态代码分析工具:这些工具通过运行代码并监控其行为来发现漏洞。它们可以模拟攻击场景,检测代码在实际运行中的安全性


专用审计工具:如SeayPHP等,它们针对特定的编程语言或框架进行优化,提供了更高效的审计功能

5.1 Java代码审计的工具推荐

SonarQube:一个开源代码质量检测平台,支持多种编程语言的静态分析,包括Java
    它提供了关于重复代码块、编码标准、单元测试、代码覆盖率、代码复杂性等方面的报告

PMD:一种开源静态源代码分析器,可报告应用程序代码中发现的问题
    它支持多种编程语言,包括Java,并提供了丰富的规则集来检测代码中的常见错误

Checkstyle:一种静态代码分析工具,用于检查Java源代码是否符合编码规则
    它基本上自动化了冗长的代码检查过程,并帮助Java开发人员执行编码标准

Burp Suite:一个集成化的Web应用程序安全测试平台,支持自动化和手动测试
    它提供了丰富的工具和功能,如代理、爬虫、入侵者、重复器、序列器等,可以帮助测试人员发现Web应用程序中的安全漏洞

FindBugs:一个Java静态分析工具,用于查找Java程序中的错误
    它可以检测出一系列常见的编程错误,如空指针引用、资源泄露等

Fortify:是一种静态代码分析工具,用于帮助开发人员发现和修复软件代码中的安全漏洞和缺陷

Fortify下载 :参考1、参考2

5.2 PHP代码审计的工具推荐

PHPStan:一个PHP静态分析工具,可以检测代码中的类型错误、未定义变量、未调用的方法等

PHP CodeSniffer:一个PHP代码风格检查工具,可以根据预定义的编码标准检查代码是否符合规范

RIPS:一个专门用于PHP代码安全审计的工具,可以检测SQL注入、XSS、文件包含等安全漏洞

Seay源代码审计系统:一款国产的PHP代码审计工具,提供了自动化的审计功能和手动审计的辅助工具

RIPS下载:参考1、参考2

Seay下载:参考1、参考2

6.最佳实践

团队合作:建立专门的审计团队,包括开发人员、安全研究人员和测试人员等
    团队成员应具备不同的技能和专业知识,以便能够全面地审计代码


知识分享:团队成员之间应共享知识和经验,以便更好地完成任务
    可以通过内部培训、技术讨论和文档共享等方式进行知识分享


持续学习:随着技术的不断发展和变化,团队成员需要不断地学习和更新自己的知识和技能
    可以通过参加行业会议、参与开源项目等方式进行持续学习


定期审计:为了保障应用程序的安全性和稳定性,需要定期进行代码审计
    这可以帮助团队及时发现并修复潜在的安全漏洞和缺陷

7.注意事项

输入验证:确保所有用户输入都经过适当的验证和过滤,以防止恶意输入导致的安全问题

输出编码:对输出到HTML、JavaScript、CSS等的内容进行编码,以防止XSS攻击

会话管理:确保会话令牌是安全的,如使用HTTPS、设置合适的会话超时时间、防止会话固定攻击等

数据库查询:使用参数化查询或预编译语句来防止SQL注入攻击

文件操作:限制对文件的访问和操作权限,确保只允许经过验证的用户上传和下载文件

错误处理:避免向用户显示详细的错误信息,特别是那些可能泄露系统信息或数据库结构的错误

安全配置:检查程序中是否存在默认配置、硬编码密码等安全隐患,确保安全配置是正确的并且不易被攻击者利用

敏感数据处理:检查程序是否妥善处理了敏感数据,如密码、密钥等,确保其安全存储和传输

权限控制:检查程序是否实现了合适的权限控制机制,确保用户只能访问其被授权的资源和功能

代码注入:检查程序是否容易受到代码注入攻击,如SQL注入、XSS等,防止攻击者利用这些漏洞执行恶意代码

8.代码审计的常用思路

一、接口与参数追踪
    接口排查(正向追踪):
        找到外部传入的参数,并对其进行追踪
        检查参数是否经过严格的校验,以及是否可能被传入高危方法
        评估代码逻辑是否存在漏洞,可能导致参数被不当使用
    危险方法溯源(逆向追踪):
        查看敏感方法的参数,并排查参数的传递与处理过程
        判断变量是否可控,并检查是否进行了严格的过滤
        逆向追踪敏感函数,如PHP中的eval()、system()、shell_exec()等,寻找不安全的函数调用实例


二、功能点审计
    功能点定向审计:
        根据经验判断哪个部分更容易出现漏洞,直接对功能点代码进行审计
        重点关注登录认证、文件上传下载、数据库操作、远程调用接口等关键功能部分
    通读全文代码:
        在时间允许的情况下,通读全文代码以了解程序的整体架构和业务逻辑
        注意查看函数集文件、配置文件、安全过滤文件等关键文件


三、第三方组件与中间件审计
    组件与中间件版本检查:
        查看第三方组件和中间件的版本,评估是否存在已知的历史漏洞
    安全配置与更新:
        检查组件和中间件的安全配置是否正确
        确认是否应用了最新的安全更新和补丁


四、自动化工具与人工研判
    自动化静态扫描工具:
        利用专门的静态分析工具(如SonarQube、Coverity、Fortify等)自动检测代码中的潜在问题
        这类工具能够快速识别出诸如SQL注入、跨站脚本攻击(XSS)、缓冲区溢出等问题
    人工研判:
        对自动化扫描工具的结果进行人工分析和确认
        结合业务逻辑和安全规范,评估潜在问题的严重性和影响范围


五、测试与监控
    黑盒测试与白盒测试:
        黑盒测试:完全不考虑程序内部结构和内部特性,只在程序接口进行测试
                 检查程序功能是否按照需求规格说明书的规定正常使用
                 以及程序是否能适当地接收输入数据而产生正确的输出信息
        白盒测试:对所有逻辑路径进行测试。测试者必须检查程序的内部结构,从检查程序的逻辑着手,得出测试数据
    运行时监控:
        采用调试器、插桩技术或特定的安全运行环境(如沙箱)实时监控代码执行过程
        监控内存访问、函数调用链、权限控制等方面的行为,发现潜在的安全漏洞


六、安全规范与框架审计
    安全编码规范:
        检查代码是否遵循相关安全编码规范和行业标准,如OWASP Top 10、CWE(Common Weakness Enumeration)等
    框架安全审计:
        审计Web应用所使用的开发框架是否存在安全性问题
        关注框架自身的安全特性,包括版本更新、已知漏洞修补及框架内部安全配置的正确设置

二:扩展

1.Java

1.1 概念 

MVC:模型(Model)、视图(View)、控制器(Controller)
    M:模型,也就是实体类,用于数据的封装和数据的传输
    V:视图,也据说GYI组件,用于数据的展示    
    C:控制,也就是事件,用于流程的控制


模型(Model)
    定义:模型是应用程序的核心数据和业务逻辑的表示。它负责处理数据的读取、写入和验证
    功能:
        表示数据库表的实体类,通过持久化框架(如Hibernate或MyBatis)与数据库进行交互
        包含业务逻辑的实现,可能通过服务层(Service Layer)进行组织


视图(View)
    定义:视图负责展示用户界面,提供用户与应用程序交互的界面
    功能:
        在Web应用中,视图通常是前端技术(如HTML、CSS、JavaScript)实现的网页
        在桌面应用中,视图可能是使用Java Swing、JavaFX等框架创建的图形用户界面
        视图从模型中获取数据,并将其展示给用户,同时接收用户的输入并将其传递给控制器


配置器/控制器(Controller)
    定义:配置器或控制器在MVC模式中充当模型和视图之间的协调者。它接收用户的请求,并根据请求的信息调用相应的模型和视图来完成业务逻辑
    功能:
        在Web应用中,控制器通常是一个Java类,使用特定的框架(如Spring MVC)处理请求
        控制器根据业务需求调用相关的服务和模型,处理业务逻辑,并选择适当的视图进行渲染
        控制器还可以处理用户输入的数据,进行验证和转换,然后将其传递给模型进行进一步处理


java目录my-java-project/  
    ├── src/  
    │   ├── main/  
    │   │   ├── java/                          #存放项目的主要Java源代码
    │   │   │   └── com/  
    │   │   │       └── example/  
    │   │   │           └── myproject/  
    │   │   │               ├── App.java       # 主类  
    │   │   │               ├── service/       # 服务层  
    │   │   │               │   └── MyService.java  
    │   │   │               ├── controller/    # 控制层(如果是Web应用)  
    │   │   │               │   └── MyController.java  
    │   │   │               └── ...            # 其他包和类  
    │   │   ├── resources/                     #存放项目的资源文件,如配置文件、属性文件、静态资源
    │   │   │   ├── application.properties     # Spring Boot等应用的配置文件  
    │   │   │   ├── logback-spring.xml         # 日志配置文件(如果使用Logback)  
    │   │   │   ├── static/                    # 存放静态资源文件目录(Javascript、CSS、图片等),在这个目录中的所有文件可以被直接访问
    │   │   │   ├── templates/                 # 存放模版文件
    │   │   │   ├── mapper/                    # 存放Mybaits的mapper.xml文件
    │   │   │   └── ...                        # 其他资源文件  
    │   │   └── webapp/                        #存放Web应用的根目录,包括JSP文件、静态资源(CSS、JavaScript、图片等)以及WEB-INF/目录(包含web.xml等配置文件)
    │   │       ├── WEB-INF/  
    │   │       │   ├── web.xml                # Web应用的部署描述符  
    │   │       │   └── ...  
    │   │       └── ...                        # 静态资源、JSP文件等  
    │   └── test/  
    │       ├── java/                          #存放项目的测试代码,通常与src/main/java/有相同的包结构 
    │       │   └── com/  
    │       │       └── example/  
    │       │           └── myproject/  
    │       │               ├── AppTest.java   # 主类的测试  
    │       │               ├── service/       # 服务层的测试  
    │       │               │   └── MyServiceTest.java  
    │       │               ├── controller/    # 控制层的测试(如果是Web应用)  
    │       │               │   └── MyControllerTest.java  
    │       │               └── ...            # 其他测试类  
    │       └── resources/                     #存放测试用的资源文件  
    │           └── ...                        # 测试用的资源文件  
    ├── pom.xml 或 build.gradle               # Maven或Gradle的构建脚本  
    ├── README.md                             # 项目说明文件  
    ├── .gitignore                            # Git忽略文件列表(如果使用Git进行版本控制)  
    ├── settings.xml                          # Maven的设置文件(可选)  
    └── ...                                   # 其他项目相关的文件和目录

1.2 漏洞关键字

 SQL注入(SQL Injection)

关键字:Statement, PreparedStatement, executeQuery(), executeUpdate(), ResultSet等

示例:
    String query = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'";  
    Statement stmt = connection.createStatement();  
    ResultSet rs = stmt.executeQuery(query);

在这个例子中,如果username或password变量未经适当处理,攻击者可以通过注入恶意的SQL代码来绕过身份验证或执行其他恶意操作
正确的做法是使用PreparedStatement来防止SQL注入

跨站脚本攻击(XSS)

关键字:response.getWriter(), out.println(), request.getParameter(), HttpServletResponse, HttpServletRequest等

示例:
    String userInput = request.getParameter("userInput");  
    response.setContentType("text/html");  
    PrintWriter out = response.getWriter();  
    out.println("<html><body>");  
    out.println("<h1>" + userInput + "</h1>"); // 未经转义的用户输入可能导致XSS  
    out.println("</body></html>");

在这个例子中,如果userInput包含恶意脚本,那么这些脚本将在用户的浏览器中执行
正确的做法是对输出进行转义或使用安全的方法来处理用户输入

文件上传漏洞

关键字:File, FileInputStream, FileOutputStream, MultipartFile, ServletFileUpload, FileItem等(在使用Spring框架时)

示例:
    // 假设使用Apache Commons FileUpload库来处理文件上传  
    DiskFileItemFactory factory = new DiskFileItemFactory();  
    ServletFileUpload upload = new ServletFileUpload(factory);  
    List<FileItem> items = upload.parseRequest(request);  
    for (FileItem item : items) {  
        if (!item.isFormField()) {  
            String fileName = item.getName();  
            File uploadedFile = new File(getServletContext().getRealPath("/") + "uploads/" + fileName);  
            item.write(uploadedFile); // 未经验证的文件上传可能导致安全问题  
        }  
    }

在这个例子中,如果攻击者上传了一个恶意文件(如包含恶意代码的脚本或可执行文件)
并且服务器没有适当的验证和过滤机制,那么攻击者可能会利用这个漏洞来执行任意代码或窃取敏感信息
正确的做法是对上传的文件进行验证和过滤,例如检查文件类型、大小、内容等

不安全的反序列化

关键字:ObjectInputStream, readObject(), Serializable接口等

示例:
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream("data.ser"));  
    Object obj = ois.readObject(); // 反序列化未受信任的数据可能导致RCE

在这个例子中,如果data.ser文件包含恶意序列化的对象,并且服务器没有适当的验证和过滤机制,那么攻击者可能会利用这个漏洞来执行任意代码
正确的做法是对反序列化的数据进行适当的验证和过滤,或者使用安全的序列化机制

命令注入(Command Injection)

关键字:Runtime.getRuntime().exec(), ProcessBuilder, Command等

示例:
    String command = "ls -l " + userInput; // userInput未经处理可能导致命令注入  
    Process process = Runtime.getRuntime().exec(command);

在这个例子中,如果userInput包含恶意命令,那么这些命令将在服务器上执行
正确的做法是对用户输入进行验证和过滤,或者使用更安全的方法来执行命令(如使用ProcessBuilder并设置适当的权限)

2.PHP

2.1 概念 

ThinkPHP框架
    ├─application           应用目录
    │  ├─common             公共模块目录(可以更改)
    │  ├─module_name        模块目录
    │  │  ├─config.php      模块配置文件
    │  │  ├─common.php      模块函数文件
    │  │  ├─controller      控制器目录
    │  │  ├─model           模型目录
    │  │  ├─view            视图目录
    │  │  └─ ...            更多类库目录
    │  │
    │  ├─command.php        命令行工具配置文件
    │  ├─common.php         公共函数文件
    │  ├─config.php         公共配置文件
    │  ├─route.php          路由配置文件
    │  ├─tags.php           应用行为扩展定义文件
    │  └─database.php       数据库配置文件
    │
    ├─public                WEB目录(对外访问目录)
    │  ├─index.php          入口文件
    │  ├─router.php         快速测试文件
    │  └─.htaccess          用于apache的重写
    │
    ├─thinkphp              框架系统目录
    │  ├─lang               语言文件目录
    │  ├─library            框架类库目录
    │  │  ├─think           Think类库包目录
    │  │  └─traits          系统Trait目录
    │  │
    │  ├─tpl                系统模板目录
    │  ├─base.php           基础定义文件
    │  ├─console.php        控制台入口文件
    │  ├─convention.php     框架惯例配置文件
    │  ├─helper.php         助手函数文件
    │  ├─phpunit.xml        phpunit配置文件
    │  └─start.php          框架入口文件
    │
    ├─extend                扩展类库目录
    ├─runtime               应用的运行时目录(可写,可定制)
    ├─vendor                第三方类库目录(Composer依赖库)
    ├─build.php             自动生成定义文件(参考)
    ├─composer.json         composer 定义文件
    ├─LICENSE.txt           授权说明文件
    ├─README.md             README 文件
    ├─think                 命令行入口文件


laravel框架
     |——app                 包含了站点的controllers(控制器),models(模型),views(视图)和assets(资源
     |——bootstrap           存放系统启动时的必要文件,这些文件会被index.php这样的文件调用。
     |——public              系统运行的公开数据,包括静态资CSS文件、js文件等
     |——vender              第三方类库  

2.2 漏洞关键字 

SQL注入(SQL Injection)

关键字:mysql_query(), mysqli_query(), PDO::query(), exec(), query() 等执行SQL查询的函数

示例:
    $user_id = $_GET['user_id'];  
    $query = "SELECT * FROM users WHERE id = $user_id";  
    $result = mysqli_query($conn, $query);

在这个例子中,如果$user_id没有经过适当的过滤或转义,攻击者可以通过修改user_id参数的值来注入恶意的SQL代码

 跨站脚本攻击(XSS)

关键字:echo, print, printf, sprintf, htmlentities(), htmlspecialchars()(未正确使用)

示例:
    $user_input = $_GET['message'];  
    echo "<div>$user_input</div>";

在这个例子中,如果$user_input包含恶意脚本,那么这些脚本将在用户的浏览器中执行
正确的做法是使用htmlentities()或htmlspecialchars()对输出进行转义

跨站请求伪造(CSRF)

关键字:表单提交(<form>标签),$_POST数组

示例:
    if ($_SERVER["REQUEST_METHOD"] == "POST") {  
        // 处理表单提交  
    }

在这个例子中,如果没有适当的CSRF防护措施(如令牌验证),攻击者可以诱导用户提交表单到攻击者控制的服务器

文件包含漏洞(File Inclusion)

关键字:include(), require(), include_once(), require_once()

示例:
    $page = $_GET['page'];  
    include("$page.php");

在这个例子中,如果$page参数没有经过适当的验证,攻击者可以包含恶意文件或执行任意代码

文件上传

代码关键字
    文件上传函数:move_uploaded_file(), copy(), fopen(), fwrite() 等用于处理文件上传的函数
    文件信息获取:$_FILES 数组,用于获取上传文件的信息,如文件名、类型、大小等
    文件类型验证:pathinfo(), mime_content_type(), getimagesize() 等函数用于验证文件的类型和内容

漏洞示例
    if ($_SERVER['REQUEST_METHOD'] == 'POST') {  
        $target_dir = "uploads/";  
        $target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);  
        if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {  
            echo "The file ". htmlspecialchars( basename( $_FILES["fileToUpload"]["name"])). " has been uploaded.";  
        } else {  
            echo "Sorry, there was an error uploading your file.";  
        }  
    }

在这个例子中,如果没有对上传的文件进行类型、大小或内容的验证,攻击者可以上传恶意文件,如PHP脚本,进而执行任意代码

 远程代码执行(RCE)

关键字:eval(), create_function(), assert(), preg_replace()(使用/e修饰符)

示例:
    $code = $_GET['code'];  
    eval($code);

在这个例子中,eval()函数会执行传入的字符串作为PHP代码,这可能导致远程代码执行

序列化漏洞

关键字:serialize(), unserialize()

示例:
    $data = serialize($_SESSION['user']);  
    // ... 存储$data到数据库 ...  
    // 从数据库读取$data并反序列化  
    $user = unserialize($data);

如果反序列化的数据来自不受信任的来源,攻击者可以构造恶意的序列化字符串来执行任意代码或触发其他漏洞

三:举例

1.Java Web SQL注入漏洞

// 存在SQL注入漏洞的代码示例  
String username = request.getParameter("username");  
String password = request.getParameter("password");  
String sql = "SELECT * FROM users WHERE username='" + username + "' AND password='" + password + "'";  
Statement statement = connection.createStatement();  
ResultSet resultSet = statement.executeQuery(sql);  
  
// 修复后的代码示例  
String username = request.getParameter("username");  
String password = request.getParameter("password");  
String sql = "SELECT * FROM users WHERE username=? AND password=?";  
PreparedStatement statement = connection.prepareStatement(sql);  
statement.setString(1, username);  
statement.setString(2, password);  
ResultSet resultSet = statement.executeQuery();
在上面的代码中,用户输入的用户名和密码直接拼接到SQL查询语句中,存在SQL注入漏洞
    攻击者可以通过输入恶意的用户名和密码来执行恶意的SQL语句

为了修复这个漏洞,我们可以使用PreparedStatement来代替拼接SQL语句,从而有效防止SQL注入攻击

比如

存在SQL注入漏洞的代码示例
    String username = request.getParameter("username");  
    String password = request.getParameter("password");  
    String sql = "SELECT * FROM users WHERE username='" + username + "' AND password='" + password + "'";  
    Statement statement = connection.createStatement();  
    ResultSet resultSet = statement.executeQuery(sql);


修复后的代码示例
    String username = request.getParameter("username");  
    String password = request.getParameter("password");  
  
    // 假设 connection 是一个有效的数据库连接对象  
    String sql = "SELECT * FROM users WHERE username=? AND password=?";  
        try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {  
        // 绑定参数  
        preparedStatement.setString(1, username); // 第一个占位符设置为username  
        preparedStatement.setString(2, password); // 第二个占位符设置为password  
  
        // 执行查询  
        try (ResultSet resultSet = preparedStatement.executeQuery()) {  
            // 处理查询结果...  
            while (resultSet.next()) {  
                // 例如,获取用户ID  
                int userId = resultSet.getInt("id");  
                // 处理用户ID...  
            }  
        }  
    } catch (SQLException e) {  
        // 处理SQL异常  
        e.printStackTrace();  
        // 可以记录日志、显示错误消息等  
    }

2.PHP SQL注入漏洞

// 存在SQL注入漏洞的代码示例  
$username = $_POST['username'];  
$password = $_POST['password'];  
$sql = "SELECT * FROM users WHERE username='$username' AND password='$password'";  
$result = mysqli_query($conn, $sql);  
  
// 修复后的代码示例  
$username = $_POST['username'];  
$password = $_POST['password'];  
$sql = "SELECT * FROM users WHERE username=? AND password=?";  
$stmt = mysqli_prepare($conn, $sql);  
mysqli_stmt_bind_param($stmt, 'ss', $username, $password);  
$result = mysqli_stmt_execute($stmt);
在上面的代码中,用户输入的用户名和密码直接拼接到SQL查询语句中,存在SQL注入漏洞
    攻击者可以通过输入恶意的用户名和密码来执行恶意的SQL语句

为了修复这个漏洞,我们可以使用预处理语句(mysqli_prepare和mysqli_stmt_bind_param)来绑定参数,从而有效防止SQL注入攻击

比如

存在SQL注入漏洞的代码示例
    $username = $_POST['username'];  
    $password = $_POST['password'];  
  
    // 假设 $conn 是一个有效的 mysqli 连接对象  
    $sql = "SELECT * FROM users WHERE username='$username' AND password='$password'";  
    $result = mysqli_query($conn, $sql);  
  
    // 处理查询结果...


修复后的代码示例
    $username = $_POST['username'];  
    $password = $_POST['password'];  
  
    // 假设 $conn 是一个有效的 mysqli 连接对象  
    $sql = "SELECT * FROM users WHERE username=? AND password=?";  
  
    // 准备 SQL 语句  
    $stmt = mysqli_prepare($conn, $sql);  
  
    // 检查语句是否成功准备  
    if ($stmt === false) {  
        die('MySQL prepare error: ' . mysqli_error($conn));  
    }  
  
    // 绑定参数('ss' 表示两个字符串参数)  
    $bind_result = mysqli_stmt_bind_param($stmt, 'ss', $username, $password);  
  
    // 检查参数绑定是否成功  
    if ($bind_result === false) {  
        die('MySQL bind param error: ' . mysqli_stmt_error($stmt));  
    }  
  
    // 执行语句  
    $execute_result = mysqli_stmt_execute($stmt);  
  
    // 检查语句执行是否成功  
    if ($execute_result === false) {  
        die('MySQL execute error: ' . mysqli_stmt_error($stmt));  
    }  
  
    // 获取结果集  
    $result = mysqli_stmt_get_result($stmt);  
  
    // 处理查询结果...  
  
    // 关闭语句  
    mysqli_stmt_close($stmt);

3.Java SQL注入漏洞

// 存在SQL注入漏洞的代码示例  
String username = request.getParameter("username");  
String password = request.getParameter("password");  
String sql = "SELECT * FROM users WHERE username='" + username + "' AND password='" + password + "'";  
Statement statement = connection.createStatement();  
ResultSet resultSet = statement.executeQuery(sql);  
  
// 修复后的代码示例  
String username = request.getParameter("username");  
String password = request.getParameter("password");  
String sql = "SELECT * FROM users WHERE username=? AND password=?";  
PreparedStatement statement = connection.prepareStatement(sql);  
statement.setString(1, username);  
statement.setString(2, password);  
ResultSet resultSet = statement.executeQuery();
在上面的代码中,用户输入的用户名和密码直接拼接到SQL查询语句中,存在SQL注入漏洞
    攻击者可以通过输入恶意的用户名和密码来执行恶意的SQL语句,如删除表、泄露数据等

为了修复这个漏洞,我们可以使用PreparedStatement来代替拼接SQL语句,从而有效防止SQL注入攻击

比如

存在SQL注入漏洞的代码示例
    String username = request.getParameter("username");  
    String password = request.getParameter("password");  
    String sql = "SELECT * FROM users WHERE username='" + username + "' AND password='" +     password + "'";  
    Statement statement = connection.createStatement();  
    ResultSet resultSet = statement.executeQuery(sql);


修复后的代码示例
    String username = request.getParameter("username");  
    String password = request.getParameter("password");  
  
    // 使用PreparedStatement和占位符  
    String sql = "SELECT * FROM users WHERE username=? AND password=?";  
    PreparedStatement preparedStatement = connection.prepareStatement(sql);  
  
    // 为占位符设置值  
    preparedStatement.setString(1, username); // 第一个占位符设置为username  
    preparedStatement.setString(2, password); // 第二个占位符设置为password  
  
    // 执行查询  
    ResultSet resultSet = preparedStatement.executeQuery();

更多推荐