什么是JSON
JSON全稱是Javascript Object Notation(對象表示法),是一種在不同平臺間傳遞數據的文本格式(數據交換格式)。常見的數據交換格式有XML、JSON兩種,我們主要研究JSON。
數據交換格式十分重要,開發人員需要使用它們來實現不同系統之間的數據交換。
JSON基于Javascript對象字面量,但是獨立于任何編程語言,真正重要的是表示法本身,所以在學習JSON之前不必先學習Javascript。當然,有Javascript基礎那是再好不過了。
JSON語法
JSON中使用鍵值對的數據結構,示例如下:
{
"name": "dawei",
"age":22,
"isMan":true
}
名稱始終需要加上雙引號,多個鍵值對使用逗號隔開。
以下兩種表示方式都是錯誤的:
{ name: "dawei" }
這是Javascript對象而不是JSON
{ 'name': 'dawei' }
這也是Javascript對象,因為在Javascript對象中允許使用單引號代替雙引號。
JSON數據交換格式可以作為獨立的文件存在于文件系統中,文件擴展名為.json。在傳遞數據的時候需要提前告知接收方接收的數據是什么類型。這時候就會涉及到媒體類型,也叫做內容類型或者MIME類型。常見的MIME類型是text/html,JSON的MIME類型是application/json。
JSON數據類型
JSON中的數據類型包括:對象、字符串、數字、布爾值、null和數組。
對象類型
JSON中的對象類型十分簡單,JSON本身就是對象,也就是被一對花括號{}
包裹的鍵值對的列表。對象可以嵌套使用。
對象可以包含多個鍵值對。鍵必須是字符串,值可以是合法的 JSON 數據類型(字符串, 數字, 對象, 數組, 布爾值或 null)。
{
"person":{
"name":"dawei",
"age":23,
"isBoy":true
}
}
字符串類型
在JSON中字符串必須并且只能使用雙引號包裹起來。在JSON中,鍵都是字符串類型。在Javascript中,使用單引號和雙引號沒有任何區別。但是JSON不是Javascript對象字面量,它只是基于Javascript對象字面量。
對于JSON解析器來說,當一個值以雙引號開始時,它希望接下來的字符串文本以另一個雙引號結尾。這意味著如果這段字符串本身包含雙引號可能會報錯。這時候我們需要使用反斜杠對字符串中的雙引號進行轉義。
{
"promo":"He say \"Bob`s the best!\" at classroom"
}
數字類型
JSON中的數字類型可以是整數、小數、負數或者是指數。
布爾類型
JSON中的布爾值僅可使用小寫形式:true或false,其他任何寫法都會報錯。
null類型
在JSON中,使用null表示一無所有、不存在等意思。
對于下面這個例子,由于對象不戴手表,所以他不存在手表顏色:
{
"freckleCount":0,
"fairy":true,
"watchColor":null
}
數組類型
數組始終應該被方括號[]
包裹。數組中的值使用逗號隔開。
這些值可以是任何合法的JSON數據類型。所以可以有字符串構成的數組、數字構成的數組、布爾值構成的數組、對象構成的數組甚至是數組構成的數組。
在數組中也可包含不同數據類型的值:
{
"eggCarton":["egg",null,"egg",5,"egg"]
}
這在JSON中也是合法的,但是我們應該避免這樣使用。因為如果我們將包含不同數據類型的數組的JSON傳遞給一個不使用Javascript的系統,那么在解析的時候很可能會報錯。
JSON 模式(Schema)
JSON中的數據通過互聯網或其他網絡傳輸到接收方,接收方會對它要接收的數據有一個預期。接收方會提供一個文檔來解釋預期的格式并且提供示例。此外,JSON模式亦可以被接收方用于傳輸方的另一端。JSON模式往往位于要接收數據的第一行,以保證數據符合要求。
我們統稱上述做法為“一致性驗證”,在這里要驗證三個方面的內容:
- 值的類型是否正確——可以具體規定一個值是數字、字符串等類型
- 是否包含所需要的數據——可以規定哪些數據是必須的,哪些是不需要的
- 值的形式是否是我們需要的——可以指定范圍、最小值和最大值
JSON Schema使用JSON來書寫,一個完整的JSON Schema格式的文件如下所示:
{
"$schema":"http://json-schema.org/draft-04/schema#",
"title":"Cat",
"properties":{
"name":{
"type":"string",
"minLength":3,
"maxLength":20
},
"age":{
"type":"number",
"description":"You cat's age in years.",
"minimum":0
},
"declawed":{
"type":"boolean"
},
"description":{
"type":"string"
}
},
"required":[
"name",
"age",
"declawed"
]
}
在這個文件中,第一個鍵值對聲明了一個schema文件,第二個鍵值對是該文件的標題,第三個鍵值對是需要包含在JSON中的屬性,第四個鍵值對指定必須包含的屬性。在屬性值中,又說明了屬性類型、對屬性的描述和值的范圍。
JSON中的安全問題
JSON本身不存在任何安全問題,但是在web中使用JSON時卻常出現兩個安全問題:跨站請求偽造和跨站腳本攻擊。
跨站請求偽造
跨站請求偽造(CSRF)是一種利用站點對用戶瀏覽器的信任而發起攻擊的方式。
這個信任其實就是用戶的登錄憑證,黑客為了得到用戶的憑證,會在用戶登錄站點的情況下向用戶發送大量的偽造“消息提醒”,目的就是為了讓用戶點擊它,訪問它帶有危險腳本的網站。一旦用戶點擊這一消息提醒、訪問該惡意網站,黑客就可獲取用戶的敏感信息(登錄憑證)實現攻擊:
<script src="https://www.yourspecialbank.com/user.json"></script>
一般安全意識較差的網站使用下列這樣的JSON URL存放敏感信息:
[
{
"username":"dawei"
},
{
"phone":"555-555-555"
}
]
這里的JSON格式是合法的,但是它十分危險,因為它也是可執行的JS腳本,黑客可以輕易的將其保存到自己站點的腳本中。
如何阻止CSRF攻擊?
首先,應該將數組作為一個值存入JSON對象,這樣數組將不再是合法的JavaScript,腳本也就無法加載它。
{
"info":[
{
"username":"dawei"
},
{
"phone":"555-555-555"
}
]
}
其次,站點應該只允許post請求,靜止使用get請求。這樣黑客就無法使用腳本中的URL了。
注入攻擊
注入攻擊都是利用系統本身的漏洞向網站注入惡意代碼來進行攻擊的。
跨站腳本攻擊
跨站腳本攻擊(XSS)是注入攻擊的一種。在使用JSON時常見的安全漏洞通常發生在Javascript從服務器獲取到一段JSON字符串并將其轉化成JavaScript對象的時候。
在JavaScript中,可以使用eval()
函數來進行這一操作:
var jsonString = '{"animal":"cat"}';
var myObject = eval("("+ jsonString +")");
alert(myObject.animal);
這好像沒什么問題,但是如果服務器或者服務器發來的JSON被攻擊,攜帶了惡意代碼,這樣的話情況將會很糟糕:
var jsonString = "alert('this is bad code')";
var myObject = eval("("+ jsonString +")");
alert(myObject.animal);
eval()
的問題在于它會將傳入的字符串無差別的編譯執行,這樣的話就會給黑客以可乘之機,很可能會給我們帶來不可估計的損失。
為了解決這一問題,引入了JSON.parse()
方法,這一函數僅解析JSON,不會執行腳本:
var jsonString = '{"animal":"cat"}';
var myObject = JSON.parse("("+ jsonString +")");
alert(myObject.animal);
未完待續...