JavaWeb應用修復存儲型XSS漏洞

一杠园、問題背景

跨站腳本攻擊的英文全稱是Cross Site Script,為了和樣式表區(qū)分,縮寫為XSS陪竿。發(fā)生的原因是網(wǎng)站將用戶輸入的內(nèi)容輸出到頁面上戏挡,在這個過程中可能有惡意代碼被瀏覽器執(zhí)行听皿⊥┐牛跨站腳本攻擊,它指的是惡意攻擊者往Web頁面里插入惡意html代碼苹熏,當用戶瀏覽該頁之時呻畸,嵌入其中Web里面的html代碼會被執(zhí)行移盆,從而達到惡意用戶的特殊目的。已知的跨站腳本攻擊漏洞有三種:1)存儲式伤为;2)反射式咒循;3)基于DOM。
1绞愚、存儲型跨站腳本攻擊涉及的功能點:用戶輸入的文本信息保存到數(shù)據(jù)庫中叙甸,并能夠在頁面展示的功能點,例如用戶留言位衩、發(fā)送站內(nèi)消息裆蒸、個人信息修改等功能點。
2糖驴、反射型跨站腳本攻擊涉及的功能點:URL參數(shù)需要在頁面顯示的功能點都可能存在反射型跨站腳本攻擊僚祷,例如站內(nèi)搜索佛致、查詢功能點。
3辙谜、基于DOM跨站腳本攻擊涉及的功能點:涉及DOM對象的頁面程序俺榆,包括(不限這些)。

漏洞危害
常見的反射型跨站腳本攻擊步驟如下:
1)攻擊者創(chuàng)建并測試惡意URL装哆;
2)攻擊者確信受害者在瀏覽器中加載了惡意URL罐脊;
3)攻擊者采用反射型跨站腳本攻擊方式安裝鍵盤記錄器、竊取受害者的cookie 蜕琴、竊取剪貼板內(nèi)容萍桌、改變網(wǎng)頁內(nèi)容(例如下載鏈接)。

存儲型跨站腳本攻擊最為常見的場景是將跨站腳本寫入文本輸入域中凌简,如留言板上炎、博客或新聞發(fā)布系統(tǒng)的評論框。當用戶瀏覽留言和評論時号醉,瀏覽器執(zhí)行跨站腳本代碼反症。

例如,在某個系統(tǒng)的文本輸入框中輸入如下的示例攻擊代碼片段<script>alert(2)</script>畔派,如果彈出如下的彈窗铅碍,則說明對應系統(tǒng)存在被XSS攻擊的風險:

image.png

加固建議:
總體修復方式:驗證所有輸入數(shù)據(jù),有效檢測攻擊线椰;對所有輸出數(shù)據(jù)進行適當?shù)木幋a胞谈,以防止任何已成功注入的腳本在瀏覽器端運行。具體如下 :

1)輸入驗證:某個數(shù)據(jù)被接受為可被顯示或存儲之前憨愉,使用標準輸入驗證機制烦绳,驗證所有輸入數(shù)據(jù)的長度、類型配紫、語法以及業(yè)務規(guī)則径密。

2)輸出編碼:數(shù)據(jù)輸出前,確保用戶提交的數(shù)據(jù)已被正確進行entity編碼躺孝,建議對所有字符進行編碼而不僅局限于某個子集享扔。

3)明確指定輸出的編碼方式:不要允許攻擊者為你的用戶選擇編碼方式(如ISO 8859-1或 UTF 8)。

4)注意黑名單驗證方式的局限性:僅僅查找或替換一些字符(如"<" ">"或類似"script"的關鍵字)植袍,很容易被XSS變種攻擊繞過驗證機制惧眠。

5)警惕規(guī)范化錯誤:驗證輸入之前,必須進行解碼及規(guī)范化以符合應用程序當前的內(nèi)部表示方法于个。請確定應用程序?qū)ν惠斎氩蛔鰞纱谓獯a氛魁。對客戶端提交的數(shù)據(jù)進行過濾,一般建議過濾掉雙引號(”)、尖括號(<秀存、>)等特殊字符捶码,或者對客戶端提交的數(shù)據(jù)中包含的特殊字符進行實體轉(zhuǎn)換,比如將雙引號(”)轉(zhuǎn)換成其實體形式"或链,<對應的實體形式是<宙项,<對應的實體形式是>以下為需過濾的常見字符:

6)對參數(shù)中的特殊字符進行轉(zhuǎn)義或者編碼,如:“’株扛、”、<汇荐、>洞就、(、=掀淘、.”等特殊字符旬蟋。

二、修復方案

2.1 統(tǒng)一對輸入?yún)?shù)進行攔截和過濾

編寫一個Filter過濾器XSSFilter.java

public class XSSFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        /*
         * //設置request字符編碼 request.setCharacterEncoding("UTF-8");
         * //設置response字符編碼 response.setContentType("text/wrapper;charset=UTF-8");
         */

        HttpServletRequest req = (HttpServletRequest) servletRequest;

        filterChain.doFilter(new XSSRequestWrapper(req), servletResponse);
    }

    @Override
    public void destroy() {

    }
}

接下來需要將該Filter注入到Spring框架中革娄,首先介紹傳統(tǒng)的xml配置的方式:

<!-- 配置過濾器 -->
    <filter>
        <filter-name>XSSFilter</filter-name>
        <filter-class>com.test.filter.XSSFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>XSSFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

如果是SpringBoot應用倾贰,可以采用如下的配置類的方式:

@Component
public class FilterRegistration {
    /**
     * 配置過濾器
     *
     * @return
     */
    @Bean
    @Order(Integer.MAX_VALUE)
    public FilterRegistrationBean xssFilterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(XSSFilter());
        registration.addUrlPatterns("/*");
        //registration.setOrder(Integer.MAX_VALUE);//過濾器順序,也可通過@Order注解配置
        //registration.addInitParameter("paramName", "paramValue");
        registration.setName("XSSFilter");
        return registration;
    }

    /**
     * 創(chuàng)建一個bean
     *
     * @return
     */
    @Bean(name = "XSSFilter")
    public Filter XSSFilter() {
        return new XSSFilter();
    }
}

這里特別說明一下拦惋,在一個web應用中匆浙,可以開發(fā)編寫多個Filter,這些Filter組合起來稱為一個Filter鏈厕妖。那么有哪些方法可以配置多個Filter之間處理的優(yōu)先級呢首尼?

如果采用XML配置的方式,web服務器根據(jù)Filter在web.xml中的注冊順序言秸,決定先調(diào)用哪個Filter软能,當?shù)谝粋€Filter的doFilter方法被調(diào)用時,web服務器會創(chuàng)建一個代表Filter鏈的FilterChain對象傳遞給該方法举畸,在doFilter方法中查排,開發(fā)人員如果調(diào)用了FilterChain對象的doFilter方法,則web服務器會檢查FilterChain對象中是否還有filter抄沮,如果有跋核,則調(diào)用第二個filter,如果沒有合是,則調(diào)用目標資源了罪。詳情參考資料1。

如果是采用配置類的方式聪全,可以通過 @Order(Integer.MAX_VALUE)注解泊藕,或者registration.setOrder(Integer.MAX_VALUE);其中,填寫的參數(shù)值越小,執(zhí)行的優(yōu)先級就越高娃圆。

撰寫一個判斷JSON格式是否合法的工具類JSONUtils:

public class JSONUtils {
    /**
     * Jackson library
     *
     * @param jsonInString
     * @return
     */
    public final static boolean isJSONValid(String jsonInString) {
        try {
            final ObjectMapper mapper = new ObjectMapper();
            mapper.readTree(jsonInString);
            return true;
        } catch (IOException e) {
            return false;
        }
    }

    public final static boolean isJSONValid1(String test) {
        try {
            JSONObject.parseObject(test);
        } catch (JSONException ex) {
            try {
                JSONObject.parseArray(test);
            } catch (JSONException ex1) {
                return false;
            }
        }
        return true;
    }
}

接下來是重頭戲玫锋,由于默認的HttpServletRequest是不允許對請求參數(shù)和請求路徑進行直接修改的(參數(shù)是只讀的),如果需要修改就需要繼承HttpServletRequestWrapper類包裝一下讼呢,在其提供的鉤子方法中修改參數(shù)的返回值撩鹿。

public class XSSRequestWrapper extends HttpServletRequestWrapper {

    private String body;
    private static String[] NO_CHECK_PARAMETER_NAME_LIST = new String[]{};

    private static String[] NO_CHECK_URL_LIST = new String[]{"/test1"};

    private static List<Pattern> NO_CHECK_URL_PATTERN_LIST = Arrays.stream(NO_CHECK_URL_LIST).map(item -> Pattern.compile(item)).collect(Collectors.toList());

    public XSSRequestWrapper(HttpServletRequest request) {
        super(request);
    }

    @Override
    public String getQueryString() {
        return SecurityUtil.escapeHtmlWithoutAmpersand(super.getQueryString());
    }

    @Override
    public Object getAttribute(String name) {
        return super.getAttribute(name);
    }

    /**
     * 重寫父類方法
     */
    @Override
    public String getHeader(String name) {
        String value = super.getHeader(name);
        return stripXSS(name, value);
    }

    /**
     * 重寫父類方法
     */
    @Override
    public String getParameter(String parameter) {
        String value = super.getParameter(parameter);
        return stripXSS(parameter, value);
    }

    /**
     * 處理query String參數(shù)
     */
    @Override
    public String[] getParameterValues(String parameter) {
        String path = super.getServletPath();
        String[] values = super.getParameterValues(parameter);

        // 排除沒有請求參數(shù)和無需校驗的路徑
        if (values == null || enableNoCheckURL(NO_CHECK_URL_PATTERN_LIST, path)) {
            return values;
        }

        int count = values.length;
        String[] encodedValues = new String[count];
        for (int i = 0; i < count; i++) {
            encodedValues[i] = stripXSS(parameter, values[i]);
        }
        return encodedValues;
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        body = HttpGetBody.getBodyString(super.getRequest());
        ServletInputStream inputStream = null;
        if (StringUtils.isNotEmpty(body)) {
            Map<String, Object> paramMap = JSON.parseObject(body);
            for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
                paramMap.put(StringEscapeUtils.escapeHtml4(entry.getKey()),
                        StringEscapeUtils.escapeHtml4(entry.getValue().toString()));
            }
            body = JSON.toJSONString(paramMap);
            inputStream = new PostServletInputStream(body);
        }
        return inputStream;
    }

    @Override
    public BufferedReader getReader() throws IOException {
        body = HttpGetBody.getBodyString(super.getRequest());
        String encoding = getCharacterEncoding();
        if (encoding == null) {
            encoding = "UTF-8";
        }
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    /**
     * 過濾參數(shù)
     *
     * @param value     參數(shù)值
     * @param parameter 參數(shù)name名
     * @return
     */
    private String stripXSS(String parameter, String value) {
        String newValue = value;

        if (newValue != null && enableNoCheckParameter(parameter)) {
            if (JSONUtils.isJSONValid(newValue)) {
//                HtmlUtils.htmlEscape(value);
//                 StringEscapeUtils.unescapeJson(value);
                newValue = SecurityUtil.escapeJsonWithoutAmpersand(value);
            } else {
//                StringEscapeUtils.escapeHtml4(value);
//                  HtmlUtils.htmlEscape(value);//spring的HtmlUtils進行轉(zhuǎn)義
                newValue = SecurityUtil.escapeHtmlWithoutAmpersand(value);
            }
        }
        return newValue;
    }

    /**
     * 判斷name是否應該攔截
     *
     * @param parameter 參數(shù)名
     * @return 不攔截返回true,攔截返回false
     */

    private boolean enableNoCheckParameter(String parameter) {
        for (String parameters : NO_CHECK_PARAMETER_NAME_LIST) {
            if (parameter.equals(parameters)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 判斷傳入的uri是否滿足patter
     *
     * @param exclusionPatterns
     * @param uri
     * @return
     */
    public static boolean enableNoCheckURL(List<Pattern> exclusionPatterns, String uri) {
        if (exclusionPatterns != null) {
            uri = uri.trim();
            for (Pattern exclusionPattern : exclusionPatterns) {
                if (isWildCardMatched(uri, exclusionPattern)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 對指定的文本進行模糊匹配悦屏,支持* 和?节沦,不區(qū)分大小寫
     *
     * @param text    要進行模糊匹配的文本
     * @param pattern 模糊匹配表達式
     * @return
     */
    public static boolean isWildCardMatched(String text, Pattern pattern) {
        Matcher m = pattern.matcher(text);
        return m.matches();
    }
}

這里重點重寫了兩個方法:getParameter和getParameterValues,getParameter方法是直接通過request獲得querystring類型的入?yún)⒄{(diào)用的方法础爬。如果是通過springMVC注解類型來獲得參數(shù)的話甫贯,走的是getParameterValues的方法。同時提供了enableNoCheckURLenableNoCheckParameter來實現(xiàn)部分參數(shù)和URL地址免過濾白名單的功能看蚜,這個白名單可以寫死叫搁,也可以通過微服務框架中常用的配置管理中心動態(tài)獲取。

這里的SecurityUtil.escapeHtmlWithoutAmpersandSecurityUtil.escapeJsonWithoutAmpersand是公司安全部提供的工具包供炎,沒有條件的可以使用如下開源的替代方案:

StringEscapeUtils.escapeHtml4這個方法來自Apache的工具類渴逻,maven坐標如下:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-text</artifactId>
    <version>1.4</version>
</dependency>

HtmlUtils.htmlEscape(value)是來自云Spring框架,maven坐標如下:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

最后編寫測試程序HelloWorldController.java:

@RestController
@RequestMapping("/hello")
public class HelloWorldController {

    @GetMapping("/say")
    public String say(@RequestParam(name = "keyword", required = false) String keyword) {
        System.out.println(">>>keyword=" + keyword);
        return keyword;
    }

    @PostMapping("/talk1")
    public String talk1(@RequestParam(value = "id", required = false) Integer id,
                        @RequestParam(value = "roleName", required = false) String roleName,
                        @RequestParam(value = "roleDes", required = false) String roleDes) {
        System.out.println(">>>id=" + id + ",roleName=" + roleName + ",roleDes=" + roleDes);
        return JSON.toJSONString(roleName);
    }

    @PostMapping("/talk2")
    public String talk2(@RequestParam(value = "id", required = false) Integer id,
                        @RequestParam(value = "roleName", required = false) RoleName roleName,
                        @RequestParam(value = "roleDes", required = false) String roleDes) {
        System.out.println(">>>id=" + id + ",roleName=" + roleName + ",roleDes=" + roleDes);
        return JSON.toJSONString(roleName);
    }
}

測試1:


image.png

測試2:


image.png

測試3:


image.png

特別說明:
通常情況下音诫,@RequestParam注解是無法直接將String轉(zhuǎn)為JavaBean對象的惨奕,如果使用X-form表單提交的數(shù)據(jù)中還有包含json格式的數(shù)據(jù),并且希望直接轉(zhuǎn)換的纽竣,可以在類中編寫一個valueOf的方法墓贿,具體實現(xiàn)可以參考下面的示例:

@Data
public class RoleName implements Serializable {
    private static final long serialVersionUID = -7166756495475187046L;

    private String key1;

    private String key2;

    public static RoleName valueOf(String jsonValue) {
        return JSON.parseObject(jsonValue, RoleName.class);
    }
}

簡單做一個小結(jié),上述實現(xiàn)方式是在Spring框架體系中增加了一級XSS相關的Filter蜓氨,由于涉及到參數(shù)的修改聋袋,選擇覆寫HttpServletRequestWrapper類來過濾和修改請求參數(shù),過濾時選擇使用到了市面上常見的一些工具類穴吹,實現(xiàn)在入?yún)⒌碾A段就對參數(shù)進行攔截和過濾幽勒,保證問題參數(shù)不會直接進入到系統(tǒng)。

2.2. 統(tǒng)一對輸出結(jié)果進行攔截和過濾

新建一個過濾器XssFilter.java

@WebFilter
@Component
public class XSSFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        XssAndSqlHttpServletRequestWrapper xssRequestWrapper = new XssAndSqlHttpServletRequestWrapper(req);
        chain.doFilter(xssRequestWrapper, response);
    }

    @Override
    public void destroy() {
    }

    /**
     * 過濾json類型的
     *
     * @param builder
     * @return
     */
    @Bean
    @Primary
    public ObjectMapper xssObjectMapper(Jackson2ObjectMapperBuilder builder) {
        //解析器
        ObjectMapper objectMapper = builder.createXmlMapper(false).build();
        //注冊xss解析器
        SimpleModule xssModule = new SimpleModule("XssStringJsonSerializer");
        xssModule.addSerializer(new XssStringJsonSerializer());
        objectMapper.registerModule(xssModule);
        //返回
        return objectMapper;
    }
}

新建一個HTTP請求的包裝類XssAndSqlHttpServletRequestWrapper.java港令,來實現(xiàn)對于參數(shù)的過濾和覆寫啥容,其中xssObjectMapper這個是后面過濾json類型才用到的。

public class XssAndSqlHttpServletRequestWrapper extends HttpServletRequestWrapper {
    private HttpServletRequest request;

    public XssAndSqlHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
        this.request = request;
    }

    @Override
    public String getParameter(String name) {
        String value = request.getParameter(name);
        if (!StringUtils.isEmpty(value)) {
            value = StringEscapeUtils.escapeHtml4(value);
        }
        return value;
    }

    @Override
    public String[] getParameterValues(String name) {
        String[] parameterValues = super.getParameterValues(name);
        if (parameterValues == null) {
            return null;
        }
        for (int i = 0; i < parameterValues.length; i++) {
            String value = parameterValues[i];
            parameterValues[i] = StringEscapeUtils.escapeHtml4(value);
        }
        return parameterValues;
    }
}

StringEscapeUtils.escapeHtml4這個方法來自Apache的工具類顷霹,maven坐標如下:

<dependency>
 <groupId>org.apache.commons</groupId>
 <artifactId>commons-text</artifactId>
 <version>1.4</version>
</dependency>

新建XssStringJsonSerializer.java實現(xiàn)自定義反序列化

/**
 * @Description 這里是通過修改SpringMVC的json序列化來達到過濾xss的目的的咪惠。
 * @Author louxiujun
 * @Date 2020/9/5 23:40
 **/
public class XssStringJsonSerializer extends JsonSerializer<String> {
    @Override
    public Class<String> handledType() {
        return String.class;
    }

    @Override
    public void serialize(String value, JsonGenerator jsonGenerator,
                          SerializerProvider serializerProvider) throws IOException {
        if (value != null) {
            String encodedValue = StringEscapeUtils.escapeHtml4(value);
            jsonGenerator.writeString(encodedValue);
        }
    }
}

最后編寫一個測試類:

@RestController
@RequestMapping(value = "/test")
public class TestController {

    @GetMapping(value = "/query")
    public Object testQuery(@RequestParam(value = "name", required = false) String name) {
        return name;
    }

    @PostMapping(value = "/json")
    public Object testJSON(@RequestBody TestRequestParam testRequestParam) {
        return testRequestParam;
    }


    @PostMapping(value = "/xform")
    public Object xform1(@RequestParam(value = "name", required = false) String name) {
        System.out.println(name);
        return name;
    }
}

測試1:測試get請求中的query String 中包含非法參數(shù)


image.png

測試2:測試HTTP POST 請求json格式的body體中含有非法參數(shù)


image.png

測試3:測試HTTP POST請求x-www-form-urlencoded格式的body體中含有非法參數(shù)


image.png

簡單小結(jié)一下,同樣采用了Filter過濾器和自定義Http wrapper的實現(xiàn)方法淋淀,該實現(xiàn)方式采用的是在返回結(jié)果返回給前端的做json序列化的時候進行參數(shù)的攔截和過濾遥昧,問題數(shù)據(jù)本質(zhì)上已經(jīng)存入系統(tǒng)中了。

參考資料

  1. 04_過濾器Filter_03_多個Filter的執(zhí)行順序
  2. 【快學SpringBoot】過濾XSS腳本攻擊(包括json格式)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市炭臭,隨后出現(xiàn)的幾起案子永脓,更是在濱河造成了極大的恐慌,老刑警劉巖鞋仍,帶你破解...
    沈念sama閱讀 222,464評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件常摧,死亡現(xiàn)場離奇詭異,居然都是意外死亡威创,警方通過查閱死者的電腦和手機落午,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來肚豺,“玉大人板甘,你說我怎么就攤上這事∠昃妫” “怎么了?”我有些...
    開封第一講書人閱讀 169,078評論 0 362
  • 文/不壞的土叔 我叫張陵寞奸,是天一觀的道長呛谜。 經(jīng)常有香客問我,道長枪萄,這世上最難降的妖魔是什么隐岛? 我笑而不...
    開封第一講書人閱讀 59,979評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮瓷翻,結(jié)果婚禮上聚凹,老公的妹妹穿的比我還像新娘。我一直安慰自己齐帚,他們只是感情好妒牙,可當我...
    茶點故事閱讀 69,001評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著对妄,像睡著了一般湘今。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上剪菱,一...
    開封第一講書人閱讀 52,584評論 1 312
  • 那天摩瞎,我揣著相機與錄音,去河邊找鬼孝常。 笑死旗们,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的构灸。 我是一名探鬼主播上渴,決...
    沈念sama閱讀 41,085評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了驰贷?” 一聲冷哼從身側(cè)響起盛嘿,我...
    開封第一講書人閱讀 40,023評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎括袒,沒想到半個月后次兆,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,555評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡锹锰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,626評論 3 342
  • 正文 我和宋清朗相戀三年芥炭,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片恃慧。...
    茶點故事閱讀 40,769評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡园蝠,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出痢士,到底是詐尸還是另有隱情彪薛,我是刑警寧澤,帶...
    沈念sama閱讀 36,439評論 5 351
  • 正文 年R本政府宣布怠蹂,位于F島的核電站善延,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏城侧。R本人自食惡果不足惜易遣,卻給世界環(huán)境...
    茶點故事閱讀 42,115評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望嫌佑。 院中可真熱鬧豆茫,春花似錦、人聲如沸屋摇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,601評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽炮温。三九已至肤京,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間茅特,已是汗流浹背忘分。 一陣腳步聲響...
    開封第一講書人閱讀 33,702評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留白修,地道東北人妒峦。 一個月前我還...
    沈念sama閱讀 49,191評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像兵睛,于是被迫代替她去往敵國和親肯骇。 傳聞我的和親對象是個殘疾皇子窥浪,可洞房花燭夜當晚...
    茶點故事閱讀 45,781評論 2 361