Java Web 工程源代碼安全審計實戰,第 1 部分

文章出處:https://www.ibm.com/developerworks/cn/java/j-lo-audit-xss/index.html
ava Web 工程源代碼安全審計實戰,第 1 部分
跨站 XSS
葉 林, 張 東升, 和 賀 新朋2015 年 11 月 02 日發布

WeiboGoogle+用電子郵件發送本頁面


3

前言
Web 應用是互聯網應用的重要形式,是金融、電信、政府部門等社會關鍵信息系統的門戶應用首選。Web 應用的組件技術和支撐手段不斷豐富變化。一般來講分為使用 Java 的、使用 PHP 的和只使用 JavaScript 實現的三大類。其中的 Java Web 發展較早,所依托的 JEE 體系比較成熟,在企業級應用中比較常見。其中的 PHP Web, 因為 PHP 開發社區提供了很多優秀的論壇網站框架,所以在論壇網站開發中比較常用。而 JavaScript 通常用于瀏覽器的前端編程,近年其 Node.js 平臺提倡在服務器端和客戶端都使用 JavaScript,一時風行。傳統的 Java Web 市場占有率較高,是本文討論的對象。
Web 應用安全不容小覷。黑客對于 Web 應用的攻擊熱點,從早年的針對服務器系統平臺,轉到針對瀏覽器。因為尋找服務器上漏洞成本高,越來越難;而瀏覽器或者客戶端的攻擊技術,比如 SQL 注入、 跨站腳本 (XSS) 等技術門檻低,攻擊成本低,相對容易實現,已顯泛濫之勢。WAP 防火墻雖然能根據內容過濾一些網絡流量,但是如果所有進出的網絡流量都需要在應用層上進行檢測,系統性能和成本付出較大。對服務器配置 HTTPS,加密客戶端和服務器之間的 HTTP 內容,雖然能保護信息隱私,但是還不足以單獨對抗除了數據竊聽之外的種類繁多的 Web 攻擊。
提高 Web 信息系統的安全性一個有效手段是對系統源代碼進行靜態掃描。這樣可以在系統代碼上線、問題發生之前,檢查系統可能存在的安全風險,防微杜漸,及時整改。
源代碼審計是一個系統工作。針對 Java Web 的靜態掃描工具很多,商用工具 Fortify 或者開源工具 Findbugs。各種工具并不健全,不同工具都具有不重復的功能,可以進行多種工具配合使用以獲得更大的檢驗覆蓋程度。同時,這些分析工具們產生的結果有可能包含誤判或者漏判。這時還需要人工審計。開發人員要經過安全開發的訓練,安全審計人員要經過審計訓練,才能熟練掌握 Java Web 源代碼安全審計方法。
“JavaWeb 工程源代碼安全審計實戰”系列基于著名的 Web 應用安全研究組織 OWASP 維護的 Java Web 開源項目 WebGoat,實戰演練對整體工程的安全審計。按照漏洞嚴重從高到低程度,抽取幾個審計結果展示。通過該系列可以了解以下幾種高危漏洞的審計思路:跨站、SQL 注入、文件路徑操縱和系統日志欺騙。
本文是 JavaWeb 工程源代碼安全審計實戰的第一部分,主要針對跨站攻擊,講解審計邏輯,用 WebGoat 工程實現攻防演練。
源代碼審計概述
安全審計人員分析重點和思路都是圍繞尋找 Source 和 Sink 展開。Source 是污染源,有害數據的入口點。Sink 是程序執行造成危害爆發部分。面對一個 Java Web 源碼工程,審計人員:1)首先要在掃描工具的幫助下,初步了解所有的 Source(有文獻也叫 Taint) 和 Sink;2)接下來追蹤污染路徑,確定 Source–Path–Sink ,邏輯再現攻擊,避免工具的漏報誤報;3)如果條件允許,可以進行漏洞利用開發,Web 滲透測試,真實攻擊;4)對于定位出的源碼漏洞,要提出整改意見;5)對修改后的源碼進行二次審計,避免整改副作用。
工程目標
對 WebGoat 工程項目的源代碼進行安全審核。WebGoat 是應用安全研究組織 OWASP 精心設計并不斷更新的,專門設計用于展示各種 Web 漏洞的 Java Web 工程。涉及語言為 Java 和 JSP,也包含部分 JavaScript。涉及文件包括這些編程語言源碼文件,也包括工程部署描述符和服務器運行環境配置文件。
審核源代碼中的漏洞,包括能引發常見 Web 應用威脅的漏洞和基于語言缺陷的漏洞,并給出解決方案。審核環境配置文件,并給出安全加固建議。
漏洞類型
Web 應用威脅
Web 攻擊和應用威脅種類繁多。早年間攻擊者對服務器系統安置可執行文件,通過本地訪問或遠程訪問這些文件,達到控制服務器目的。現在更傾向攻擊客戶端,因為技術門檻低,實施成本小。國際組織 OWASP 按危害程度排出前十名 Web 應用安全威脅,成為業內標桿參考。通過代碼審計發現程序薄弱點后,整改這些薄弱點,可以對抗部分 Web 應用威脅。
表 1.OWASP Top 10 2013
Web 應用安全
威脅種類

威脅實施途徑

導致結果

A1. 注入
(SQL 注入、OS 命令注入、XPATH 注入、LDAP 注入、JSON 注入、URL 注入)

頁面輸入,拼湊字符串,語句執行

代碼邏輯依賴于外部輸入,可導致不可預期的行為

A2. 失效的身份認證和會話管理

改變 cookie 內容

扮演成為其他用戶身份

A3. 跨站腳本(XSS)

利用 URL 夾帶/附加 JavaScript 執行腳本,嵌入木馬代碼

訪問服務端敏感數據或者威脅客戶本地安全

A4. 不安全的直接對象引用

URL 參數解碼

猜測 URL 對象內容

A5. 安全配置錯誤

修改權限配置文件

越權訪問修改執行,搗毀服務器或應用程序

A6. 敏感數據暴露

各種

不可預料的問題

A7. 功能級別訪問控制缺失

文件路徑操縱

搗毀服務器或應用程序

A8. 跨站請求偽造(CSRF)

誘騙點擊惡意 URL

扮演成為合法用戶身份

A9. 使用已知易受攻擊組件

使用第三方組件,不注意維護

不可預料的問題

A10. 未驗證的重定向和轉發

登錄頁面跳轉

用戶密碼泄露

Java 和 JSP 語言代碼缺陷
能工作的代碼并不代表好代碼。編程語言天然的代碼缺陷,易引導開發者犯錯,造成程序不健壯,是代碼審計的靶點。
部署描述符和生產環境配置問題
Java Web 應用工程部署并運行在服務器環境中,所以代碼安全審計除了檢查編程語言(Java, JSP,JavaScript)文件,還要檢查應用和服務器的配置文件,對生產環境進行安全加固。
源代碼審核結果綜述
本次源代碼審計工作共檢查 WebGoat 工程代碼行數 39,422 行,包括 Java(34,349 行), JavaScript(632 行)和 JSP(4441 行)。
共發現累計上百個代碼缺陷。其中接近一半高危缺陷。具體情況如下表所示。
表 2. 源代碼審計結果綜述表


Web 應用威脅之跨站 (XSS)
技術原理
WebGoat 工程源代碼有跨站的問題。跨站的本質在于執行腳本,讓受害者瀏覽器執行攻擊者設計的 JavaScript/Flash/Html 等。
跨站發生的條件有兩個:1)來自不可信數據源的污染數據。在反射性跨站攻擊中,污染數據來自頁面請求。在存儲型跨站中,污染數據來自服務器后臺數據庫。2)污染數據未經檢驗就被作為動態內容提交給用戶瀏覽器執行。
問題分析之反射跨站 ReflectedXSS.java:187
源代碼審計發現 ReflectedXSS.java 第 187 行 addElement () 方法向瀏覽器發送未經驗證的數據,如果這個數據是來自攻擊者的 JavaScript 代碼,瀏覽器會執行攻擊者命令。
本例中,完成一次完整的污染傳播 Source-Path-Sink 三步驟如下:
ParameterParser.java 第 615 行使用 getParameterValues() 從網頁 request 獲取數據,代碼片段如下:
圖 1. 污染數據來自不可信任的數據源 (Source)

ReflectedXSS.java 第 597 行使用 getRawParameter() 傳播污染數據,代碼段如下:
圖 2. 污染數據在程序體內部沿路徑傳播(Path)

ReflectedXSS.java 第 75 行使用來自污染源 field1 的數據對 param1 賦值,并用 param1 構造頁面元素,代碼段如下:
圖 3. 污染源 field1 對 param1 賦值
點擊查看大圖

下圖來自 Fortify 分析工具,紅色箭頭指示傳播路徑,右紫色框代表 Source,左紅色框代表 Sink。
圖 4. 污染數據傳播路徑圖

點擊查看大圖

SqlStringInjection.java 第 187 行 addElement () 使用了來自不可信數據源的污染數據構建頁面元素,代碼片段如下:
圖 5. 污染數據被用來構造頁面元素 (Sink)

點擊查看大圖

至此污染源,路徑,爆發點(Source-Path-Sink)確定。注意到污染數據在傳播路徑上,沒有校驗過濾過,滿足技術原理中 XSS 攻擊條件:1) 來自不可信數據源的污染數據;2) 污染數據未經檢驗就被作為動態內容提交給用戶瀏覽器執行。代碼審計邏輯上可以判斷這是一個 XSS 漏洞。
攻擊場景
在已部署的 WebGoat 工程,啟動生產環境(WebGoat 工程使用見附錄)。
在左側導航目錄下點選" Reflected XSS Attacks", 在右側頁面最下方的文本框 Enter your three digit access code:輸入<script>alert('Hacked.')</script>。
觀察彈框出現。彈框腳本的成功執行證明頁面存在跨站漏洞。
圖 6. 反射跨站攻擊場景


彈框腳本不具強大攻擊力,但是其他惡意腳本可以作為系列高級可持續攻擊 (APT) 的組成部分。比如先誘騙受害者訪問攻擊者構造的 html 頁面元素 Image,而 Image.src 屬性要求瀏覽器訪問某個地址 (URL),該 URL 是惡意腳本讀取受害者當前用戶頁面的 session、cookie 等敏感信息并動態拼接而成,形如 http://hacker.com&victomCookie=cookie。這些敏感信息被發送到攻擊者可控制的 URL,被攻擊者讀取。在金融操作中,用戶帳號、余額等敏感信息可以這樣被泄露。
XSS 攻擊永遠不止步于彈框、收集頁面 cookie 信息。XSS 的本質在于瀏覽器端執行腳本。有人甚至說 覽 XSS is the New Buffer Overflow, JavaScript Malware is the new shell code”。這是類比傳統對服務器的攻擊手法:在服務器操作系統堆棧中用緩沖區溢出,改寫程序返回地址的方法,把執行程序引向執行惡意代碼。這種傳統的針對服務器的攻擊實施門檻高。XSS 攻擊在受害者環境引導瀏覽器執行惡意代碼。進而通過攻擊用戶本地電腦其他服務。跨站攻擊實施門檻低,攻擊力強大,需要認真審計源碼,規避 XSS 漏洞。
以上審計分析的反射跨站,污染數據直接來自受害者瀏覽器頁面請求 web request,攻擊要臨機操作,執行有難度。下面審計分析存儲跨站。存儲跨站的攻擊者和受害者使用各自現場瀏覽器,執行攻擊相對容易。
問題分析之存儲跨站 StoredXSS.java:230
源代碼靜態掃描發現 StoredXSS.java 第 230 行 makeCurrent() 方法向瀏覽器發送未經驗證的數據,如果這個數據是來自攻擊者的 JavaScript 代碼,瀏覽器會執行攻擊者命令。本例中,完成一次完整的污染傳播 Source-Path-Sink 三步驟如下:
StoredXss.java 第 218 行使用 executeQuery() 從數據庫讀取數據,代碼片段如下:
圖 7. 污染數據來自不可信任的數據源 (Source)
點擊查看大圖

本案例數據庫是不可信任的數據源,因為進一步分析數據庫發現數據來自未經校驗的網頁用戶輸入。
更進一步分析數據庫的數據來源:
ParameterParser.java 第 615 行使用 getParameterValues() 從網頁 request 獲取數據,代碼片段如下:
圖 8. 從網頁獲取數據


StoredXss.java 第 97 行執行 getRawParameter() 從網頁 request 獲取數據,付給 message。第 110 行執行 execute(),向數據庫寫入 message 。代碼片段如下:
圖 9. 向數據庫寫數據
點擊查看大圖

觀察數據傳播過程,沒有對寫入數據的校驗過濾。
從數據庫中讀取到的污染數據,在程序體內流轉后到達爆發點,即紅色框代表的 Sink。下圖來自 Fortify 分析工具:
圖 10. 污染數據在程序體內部沿路徑傳播(Path)


StoredXss.java 第 230 行 makeCurrent() 使用了來自不可信數據源的污染數據 results,構建頁面元素,代碼片段如下:
圖 11. 污染數據被用來構造頁面元素 (Sink)

至此污染源,路徑,爆發點(Source-Path-Sink)確定。注意到污染數據在傳播路徑上,沒有被校驗過濾過,滿足 XSS 攻擊的兩個條件:1) 來自不可信數據源的污染數據。2) 污染數據未經檢驗就被作為動態內容提交給用戶瀏覽器執行。所以代碼審計邏輯上可以判斷這是一個 XSS 漏洞。被污染的數據存放在服務器數據庫中。進一步推斷這是存儲型 XSS 漏洞。
攻擊場景
在已部署的 WebGoat 工程,啟動生產環境。(WebGoat 工程使用見附錄)
模擬攻擊者登錄,在左側導航目錄下點選" Stored XSS Attacks", 在 Title 文本框輸入" anyTitle", 在 Message 文本框輸入"<script>alert('Hacked.')</script>"點擊提交按鈕。污染數據存入后臺數據庫。攻擊完成。
圖 12. 存儲跨站攻擊場景
點擊查看大圖

受害者啟動一個新瀏覽器,在左側導航目錄下點選" Stored XSS Attacks", 在頁面上找到并點擊" anyTitle"字樣超鏈接,觀察彈框出現。證明頁面存在執行惡意腳本的能力。
解決方案
快速修復
解決 WebGoat 工程的反射跨站問題,可以在 ReflectedXSS.java 第 75 行使用 WebGoat 自實現的 HtmlEncoder.encode() 對污染數據編碼處理后再輸出。代碼片段如下:
圖 13. 整改反射跨站的代碼

點擊查看大圖

類似的,解決 WebGoat 工程的存儲跨站問題,可以在 StoredXSS.java 使用以下代碼片段:
圖 14. 整改存儲跨站的代碼


整改代碼編譯部署后,WebGoat 生產環境的攻擊場景不再出現。
以上代碼的整改思路是”輸出編碼”。對輸出到客戶端的字符串進行編碼可以使系統更加安全。
將“<”編碼為“<”,“"”編碼為“"”,這樣”<script>”保存后最終存儲的會是:“<script&gt”;在展現時瀏覽器會對這些字符轉換成文本內容<script>顯示,而不是去執行一段可執行的代碼。
除了“輸出編碼”,XSS 跨站的解決方法還有“輸入驗證和數據凈化”。以下系統講解 XSS 各種解決方案。
舉一反三
XSS 跨站問題的根本原因是對輸入參數處理不當。解決思路有兩條:“輸入驗證數據凈化”和“輸出編碼”。
基于 HTTP 通信協議的 Web 應用中,服務器先接收請求,再應答請求把字符串輸出到客戶端。對 XSS 跨站的防范應該部署在服務器輸入和輸出兩個階段。當服務器接收輸入請求時,進行數據驗證和凈化。當服務器輸出應答請求時,對應答字符串進行編碼。“輸入驗證”和“輸出編碼”可以獨立實施,也可互為補充。
輸入驗證和數據凈化
輸入驗證和數據凈化一般使用過濾器,基于黑白名單進行數據凈化。使用過濾器有三點需要注意。

  1. 首先強調過濾要在服務器端進行,客戶端的驗證容易被繞過。只要攻擊者用抓包工具捕獲從客戶端發送到服務器的報文、修改并重放,就有可能攻擊成功。在服務器端代碼已經實施過濾的基礎上,可以建議在客戶端也可以進行過濾,多次過濾的目的是減少服務器的負荷。
  2. 其次要注意先標準化,然后再檢驗字符串。
    因為不同版本 unicode 編碼集的不同,所以同一個字符沒有唯一的二進制表達,存在二義性。比如尖括號<>,在一種 unicode 版本中可能表達為“\uFE64” “\uFE65”, 在另外 unicode 版本可能表達為另外形式。
    通常用 NFKC 格式對任意編碼的字符串進行標準化,消除二義性(當然還有 NFKD 標準化形式,總要選一種)。代碼如下:
    String s =“\uFE64”+“script”+“\uFE65”;
    s = Normalizer.normalize(s, Form.NFKC);
    pattern.matcher(s)
  3. 還要注意過濾內容必須充分。按照安全權限最小化的思想,盡量使用白名單。因為黑名單列舉有限,掛一漏百。白名單可以結合業務邏輯進行編排,比如年齡字段只允許輸入數字。如果業務邏輯不容易枚舉白名單,只能通過黑名單過濾,那么要保證過濾內容的充分,一級防范至少要過濾掉“<”、“>”、“'”、“"”和“\”五個特殊字符。代碼如下:
    Pattern patter = Pattern.compile(“<|>|’|”|\”)
    更深一步的防范可以考慮以下的內容:
    過濾“<”、“>”將用戶輸入放入引號間,基本實現數據與代碼隔離;
    過濾雙引號,防止用戶跨越許可的標記,添加自定義標記;
    過濾 TAB 和空格,防止關鍵字被拆分;
    過濾 script 關鍵字;
    過濾&# 防止 HTML 屬性繞過檢查。
    4 過濾設計要綜合考量性能因素,選擇多次過濾或者單字符過濾。
    首先認識到過濾的副作用,英語語義可能破壞,yours’ 會被過濾為 yours。其次有時需要多次過濾,例如<scrip<script>t>過濾掉<script>后還是<script>。需要注意多個過濾器的先后次序。當多個過濾器一起生效時,有可能后進行的過濾導致前面的過濾失效。例如過濾器 1 要過濾 ABC,過濾器 2 要過濾 DEF,那么 ABDEFC 在依次通過 1,2 過濾器后變成了 ABC,這樣相當于繞開過濾器 1。所以如果性能許可,要單獨單字符過濾。
    以上在服務器輸入端進行整改。下面講述在服務器輸出端的整改方法。
    輸出編碼 (Html encode)
    以下三方法任選其一
  4. 開發者自己實現編碼輸出,可以參考 WebGoat 工程源碼 HtmlEncoder.java,也可以簡要實現如下:
    private String cleanXSS(String value) {
    value = value.replaceAll("<", "& lt;");
    value=value.replaceAll(">", "& gt;");
    value = value.replaceAll("'", "& #39;");
    // to be augmented..
    return value;
    }
  5. 也可以使用 Apache 的 commons-lang.jar 提供系統庫函數:
    StringEscapeUtils.escapeHtml(str);
    HTML 的輸出編碼是防止注入 XSS 的通用手法,除了 Java,其他語言都有提供對 HTML 的輸出編碼:
    PHP 的 htmlentities() 或是 htmlspecialchars()。
    Python 的 cgi.escape()。
    ASP 的 Server.HTMLEncode()。
    基于.net 開發的 Web 應用,系統庫函數 AntiXss.HtmlEncode Java 的 xssprotect(Open Source Library)。
    Node.js 的 node-validator。
    3.WebGoat 是獨立實施的 Web 應用。但是現實 Web 應用可以基于一些框架,比如 Spring Struts Hiberante。如果使用 Spring 框架進行 Java Web 開發,可以在 web.xml 文件中設置 HTML encode,在 JSP 文件頁面元素 form 中確定實施。
    web.xml 加上:
    <context-param>
    <param-name>defaultHtmlEscape</param-name>
    <param-value>true</param-value>
    </context-param>
    forms 加上:
    <spring:htmlEscape defaultHtmlEscape="true" />
    縱深防御
    除了通用的輸入驗證和輸出編碼防御思路。有些特定的頁面元素,也有自己的防 XSS 屬性設置。
  6. 設置 cookie 的 HttpOnly 屬性
    XSS 通常被用于偷取 cookie 內容。在設置 cookie 時使用 HttpOnly 參數,限制 cookie 作為 DOM 對象存取。
  7. 設置<frame>的 security 屬性
    IE6 以后的版本提供<frame>和<iframe>新的 security 屬性,可以針對個別的 frame 或 iframe 設定 Restricted Sites,在 Restricted Sites 區塊內將不支持 scripts 語法的執行。代碼片段如下:
    <frame security="restricted"src="//www.somesite.com/somepage.htm"></frame>
    結束語
    本文是 JavaWeb 工程源代碼安全審計實戰的第 1 部分,主要針對跨站攻擊,講解審計邏輯,用 WebGoat 工程實現攻防演練。JavaWeb 工程源代碼安全審計實戰的第 2 部分,將審計 SQL 注入攻擊,歡迎閱讀。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,578評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,701評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,691評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,974評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,694評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,026評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,015評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,193評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,719評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,442評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,668評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,151評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,846評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,255評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,592評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,394評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,635評論 2 380

推薦閱讀更多精彩內容