一、Json简介
JSON 是存储和交换文本信息的语法,是轻量级的文本数据交换格式。类似xml,但JSON 比 XML 更小、更快,更易解析。所以现在接口数据传输都采用json方式进行。JSON 文本的 MIME 类型是 “application/json”。
json语法
- 数据在名称/值对中
- 数据由逗号分隔
- 大括号保存对象
- 中括号保存数组
JSON 值
JSON 值可以是:
- 数字(整数或浮点数) {“age”:30 }
- 字符串(在双引号中) {“uname”:“yang”}
- 逻辑值(true 或 false) {“flag”:true }
- 数组(在中括号中){“sites”:[{“name”:“yang”},{“name”:“ming”}]}
- 对象(在大括号中)JSON 对象在大括号({})中书写: null { “runoob”:null }
Json-demo:
{"users": {"user": [{"id": "1","username": "admin","passwd": "admin888"},{"id": "2","username": "root","passwd": "root123"},{"id": "3","username": "system","passwd": "system456"}]}
}
二、JSON注入
和xml注入一样,只是数据表现形式不同而已。
JSON注入是指应用程序所解析的JSON数据来源于不可信赖的数据源,程序没有对这些不可信赖的数据进行验证、过滤,如果应用程序使用未经验证的输入构造 JSON,则可以更改 JSON 数据的语义。在相对理想的情况下,攻击者可能会插入无关的元素,导致应用程序在解析 JSON数据时抛出异常。本文以JAVA语言源代码为例,分析“JSON注入”漏洞产生的原因以及修复方法。该漏洞的详细介绍请参见 CWE ID 91: XML Injection (aka Blind XPath Injection)
(http://cwe.mitre.org/data/definitions/91.html)。
<?phpheader('content-type:text/html;charset=utf-8');if(isset($_POST['json'])){$json_str=$_POST['json'];$json=json_decode($json_str);if(!$json){die('JSON文档格式有误,请检查');}$username=$json->username;//$passwd=$json->passwd;$mysqli=new mysqli();$mysqli->connect('localhost','root','root');if($mysqli->connect_errno){die('数据库连接失败:'.$mysqli->connect_error);}$mysqli->select_db('user');if($mysqli->errno){dir('打开数据库失败:'.$mysqli->error);}$mysqli->set_charset('utf-8');$sql="SELECT username,paawd FROM users WHERE username='{$username}'";$result=$mysqli->query($sql);if(!$result){die('执行SQL语句失败:'.$mysqli->error);}else if($result->num_rows==0){die('查询结果为空');}else {$array1=$result->fetch_all(MYSQLI_ASSOC);echo "用户名:{$array1[0]['username']},密码:{$array1[0]['paawd']}";}$result->free();$mysqli->close();}
?>
和SQL注入一样,插入注入语句。但要注意一点是对影响json语句的要进行转义,如双引号、花括号等。
JSON 注入的危害
攻击者可以利用JSON注入漏洞在JSON数据中插入元素,从而允许JSON数据对业务非常关键的值执行恶意操作,严重的可能导致XSS和动态解析代码。
从2018年1月至2019年6月,CVE中共有18条漏洞信息与其相关。部分漏洞如下:
示例代码
示例源于 WebGoat-8.0.0.M25 (https://www.owasp.org/index.php/Category:OWASP_WebGoat_Project),源文件名:CSRFFeedback.java。
上述示例代码是接收请求参数 feedback 中的 JSON 数据,并将 JSON 数据转换为对象。第35行,声明一个 ObjectMapper 类的实例 objectMapper 用于处理 JSON 数据。第40行在方法 completed 中声明了要获取的参数 feedback,在第42行将请求参数 feedback 的字节数组值和 Map.class 作为参数传入实例 feedback 的 readValue() 方法,用于将 JSON 数据转换为 Map 集合类的对象。
由于 JSON 是根据引号、冒号、逗号和花括号区分各字符意义的,当JSON格式为{“username”:“admin”,“password”:“adminpassword”}时,程序可正确解析该 JSON 数据。数据为{“username”:“admin”,“password”:“admin"password”}时,其中 admin"password 中的引号会破坏整个JSON的结构,导致 JSON 解析失败,无法转换为指定对象。
使用代码卫士对上述示例代码进行检测,可以检出“JSON注入”缺陷,显示等级为高。从跟踪路径中可以分析出数据的污染源以及数据流向,在代码行第42行报出缺陷。如图1所示:
修复代码
在上述修复代码中,使用 com.fasterxml.jackson.core.io 包下的JsonStringEncoder 类来对 JSON 数据进行操作,在第43行获取 JsonStringEncoder 的对象 encoder,调用 quoteAsUTF8 方法将 feedback中的数据按照 JSON 标准处理并编码为 UTF-8,将结果返回为字节数组。将转换后的字节数组作为参数与 Map.class 传入 readValue 方法。使用 JSON 标准对 JSON 数据进行处理,防止 JSON 注入。
使用代码卫士对修复后的代码进行检测,可以看到已不存在“JSON注入”缺陷。如图2所示:
图2:修复后检测结果
如何避免 JSON 注入
检查程序逻辑,根据实际需求对数据进行合理过滤和安全校验,以避免产生JSON注入。