WEB前端 [编码] 规则浅析
前言
说到前端安全问题,首先想到的无疑是XSS(Cross Site Scripting,即跨站脚本),其主要发生在目标网站中目标用户的浏览器层面上,当用户浏览器渲染整个HTML文档的过程中出现了不被预期的脚本指令并执行时,XSS就会发生。XSS有三类:
- 反射型XSS:发出请求时,XSS代码出现在URL中,作为输入提交到服务端,服务端解析后响应,在响应内容中出现这段XSS代码,最后浏览器解析执行,此过程就像一次反射;
- 存储型XSS:它与反射型XSS的差别仅在于--提交的XSS代码会存储在服务端,下次请求目标页面时不用再提交XSS代码。典型的例子就是留言板XSS,用户提交一条包含XSS代码的留言存储到数据库,再次查看留言时会显示出来,进而触发XSS攻击。
- DOM XSS:它与以上两种XSS不同之处在于--DOM XSS不需要服务器解析响应的直接参与,触发XSS靠的就是浏览器端的DOM解析,完全在客户端发生。
XSS诱发原因有很多,很多网站做了各种针对性工作防御XSS,浏览器厂商也做了很大努力。为了防御XSS,很多可能触发XSS的敏感字符会被过滤或转义,而这些转义规则也是各不相同的。不了解这些不同的编码规则,会给我们日常编程造成很大的困惑,本文是针对各种编码规则写的一篇总结,希望给大家一些帮助。
1.字符编码
字节:一字节由8位二进制数组成。
字符:肉眼看到的一个文字或者符号单元就是一个字符,一个字符可能对应1~n个字节。
字符集:一些字符组成的合集,如ASCII字符集就是由128个字符组成,基本上就是键盘上的英文字符(包括控制符)。
字符集编码:一种字符集往往都对应于一种字符编码方式。一个字符对应1~n字节是由字符集与编码决定的,说白了字符集编码就是一种字符与编码值的映射关系。
常见的编码方式有ASCII,GB2312,GBK,Big5,UTF-8,UTF-7等。不同的编码方式,会产生不同的编码结果,比如以GBK编码的文件用UTF-8打开就会出现乱码问题。如果文件是英文的,并不会出现乱码。因为,在GBK中ASCII字符编码是一个字节,继承自ASCII码,而汉字编码是两个字节;在UTF-8中ASCII字符依然是一个字节,和ASCII码一样,而汉字编码是三或四个字节;所以,关于ASCII字符并不存在转码问题,其表示方式一致,而汉字需要重新转码。
其他编码方式都是兼容ASCII的,ASCII字符编码方式相同。
注:有些安全问题是由字符集使用不当造成的,所以在实际开发中需要选择合适的编码规则。
2.URL编码
URL编码是一种多功能技术,可以通过它来战胜多种类型的输入过滤器。URL编码的最基本表示方式是使用问题字符的十六进制ASCII编码来替换它们,并在ASCII编码前加%。例如,单引号字符的ASCII码为0x27,其URL编码的表示方式为%27。
URL的一种常见的组成模式如下:
- <scheme>://<netloc>/<path>?<query>#<fragment>
RFC3986文档规定,Url中只允许包含英文字母(a-zA-Z)、数字(0-9)、-_.~4个特殊字符以及所有保留字符。
保留字符:Url可以划分成若干个组件,协议、主机、路径等,RFC3986中指定了以下字符为保留字符:! * ' ( ) ; : @ & = + $ , / ? # [ ]。
不安全字符:还有一些字符,当他们直接放在Url中的时候,可能会引起解析程序的歧义。这些字符被视为不安全字符,原因有很多。
- 空格:Url在传输的过程,或者用户在排版的过程,或者文本处理程序在处理Url的过程,都有可能引入无关紧要的空格,或者将那些有意义的空格给去掉;
- 引号以及<>:引号和尖括号通常用于在普通文本中起到分隔Url的作用;
- #:通常用于表示书签或者锚点;
- %:百分号本身用作对不安全字符进行编码时使用的特殊字符,因此本身需要编码;
- {}|\^[]`~:某一些网关或者传输代理会篡改这些字符。
需要注意的是,对于Url中的合法字符,编码和不编码是等价的,但是对于上面提到的这些字符,如果不经过编码,那么它们有可能会造成Url语义的不同。因此对于Url而言,只有普通英文字符和数字,特殊字符$-_.+!*'()还有保留字符,才能出现在未经编码的Url之中。其他字符均需要经过编码之后才能出现在Url中。
如何进行URL编码?
Url编码通常也被称为百分号编码(Url Encoding,also known as percent-encoding),是因为它的编码方式非常简单,使用%百分号加上两位的字符——0123456789ABCDEF——代表一个字节的十六进制形式。Url编码默认使用的字符集是US-ASCII。例如a在US-ASCII码中对应的字节是0x61,那么Url编码之后得到的就是%61,我们在地址栏上输入http://g.cn/search?q=%61%62%63,实际上就等同于在google上搜索abc了。又如@符号在ASCII字符集中对应的字节为0x40,经过Url编码之后得到的是%40。
对于非ASCII字符,需要使用ASCII字符集的超集进行编码得到相应的字节,然后对每个字节执行百分号编码。对于Unicode字符,RFC文档建议使用utf-8对其进行编码得到相应的字节,然后对每个字节执行百分号编码。如"中文"使用UTF-8字符集得到的字节为0xE4 0xB8 0xAD 0xE6 0x96 0x87,经过Url编码之后得到"%E4%B8%AD%E6%96%87"。
如果某个字节对应着ASCII字符集中的某个非保留字符,则此字节无需使用百分号表示。例如"Url编码",使用UTF-8编码得到的字节是0x55 0x72 0x6C 0xE7 0xBC 0x96 0xE7 0xA0 0x81,由于前三个字节对应着ASCII中的非保留字符"Url",因此这三个字节可以用非保留字符"Url"表示。最终的Url编码可以简化成"Url%E7%BC%96%E7%A0%81" ,当然,如果你用"%55%72%6C%E7%BC%96%E7%A0%81"也是可以的。
注:不同的浏览器及不同的浏览器版本可能采用不同的URLEncode编码规则,其编码的敏感字符可能不完全相同。
3.HTML编码
HtmlEncode:是将html源文件中不容许出现的字符进行编码,通常是编码以下字符:"<"、">"、"&"、"""、"'"等;
HtmlDecode:跟HtmlEncode恰好相反,解码出原来的字符。
为了防止XSS攻击,有的浏览器本身就会对某些HTML标签内的内容进行处理,这样我们就可以利用某些浏览器对这些标签包含内容的转义完成HTML编解码。并不是所有的浏览器都会为标签内置这样的功能,但绝大多数浏览器都会支持JS,那么使用JS就是完成HTML编解码就有更好的适用性。
下面是一些需要编码的字符对应关系举例:
- &--&
- <--<
- >-->
- 空格--
- “--"
(还有一些其他的特殊字符,其转义对应关系,请参考:HTML转义字符)
具体实现代码如下:
- var HtmlUtil = {
- /*1.用浏览器内部转换器实现html转码*/
- htmlEncode: function(html) {
- //1.首先动态创建一个容器标签元素,如DIV
- var temp = document.createElement("div");
- //2.然后将要转换的字符串设置为这个元素的innerText(ie支持)或者textContent(火狐,google支持)
- (temp.textContent != undefined) ? (temp.textContent = html) : (temp.innerText = html);
- //3.最后返回这个元素的innerHTML,即得到经过HTML编码转换的字符串了
- var output = temp.innerHTML;
- temp = null;
- return output;
- },
- /*2.用浏览器内部转换器实现html解码*/
- htmlDecode: function(text) {
- //1.首先动态创建一个容器标签元素,如DIV
- var temp = document.createElement("div");
- //2.然后将要转换的字符串设置为这个元素的innerHTML(ie,火狐,google都支持)
- temp.innerHTML = text;
- //3.最后返回这个元素的innerText(ie支持)或者textContent(火狐,google支持),即得到经过HTML解码的字符串了。
- var output = temp.innerText || temp.textContent;
- temp = null;
- return output;
- },
- /*3.用正则表达式实现html转码*/
- htmlEncodeByRegExp: function(str) {
- var s = "";
- if (str.length == 0) return "";
- s = str.replace(/&/g, "&");
- s = s.replace(/</g, "<");
- s = s.replace(/>/g, ">");
- s = s.replace(/ /g, " ");
- s = s.replace(/\'/g, "'");
- s = s.replace(/\"/g, """);
- return s;
- },
- /*4.用正则表达式实现html解码*/
- htmlDecodeByRegExp: function(str) {
- var s = "";
- if (str.length == 0) return "";
- s = str.replace(/&/g, "&");
- s = s.replace(/</g, "<");
- s = s.replace(/>/g, ">");
- s = s.replace(/ /g, " ");
- s = s.replace(/'/g, "\'");
- s = s.replace(/"/g, "\"");
- return s;
- }
- };
注:会自动对其包含的敏感字符进行编码,具备HTMLEncode功能的标签有:
- <title></title>;
- <textarea></textarea>;
- <xmp></xmp>;
- <iframe></iframe>;
- <noscript></noscript>;
- <noframes></noframes>;
- <plaintext></plaintext>等。
4.JavaScript编码
上边讲述了HTML编解码的知识,一个网站并不仅仅包含HTML,还会带有JS代码,JS也有一些敏感的字符需要进行处理,当HTML和JS混在一起时,它们会采用什么样的规则进行编解码呢?下面有四个实例,可以了解一下其运作机理。
样例1
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8"/>
- <title>样例1</title>
- </head>
- <body>
- <input type="button" id="XSS" value="XSS" onclick="document.write('<img src=@ onerror=alert(1234) />')"/>
- </body>
- </html>
运行结果:弹出-1234。
样例2
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8"/>
- <title>样例2</title>
- <script type = "text/javascript" >
- function HtmlEncode(str) {
- var s = "";
- if (str.length == 0) return "";
- s = str.replace(/&/g, "&");
- s = s.replace(/</g, "<");
- s = s.replace(/>/g, ">");
- s = s.replace(/ /g, " ");
- s = s.replace(/\'/g, "'");
- s = s.replace(/\"/g, """);
- return s;
- }
- </script>
- </head>
- <body>
- <input type="button" id="XSS" value="XSS" onclick="document.write(HtmlEncode('<img src=@ onerror=alert(1234) />'))" />
- </body>
- </html>
运行结果:页面输出字符串--<img src=@ onerror=alert(1234) />。(chorme下没有>输出,应该进行过滤了)
样例3
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8"/>
- <title>样例3</title>
- </head>
- <body>
- <input type="button" id="XSS" value="XSS" onclick="document.write('<img src=@ onerror=alert(1234) />')" />
- </body>
- </html>
运行结果:弹出-1234。
样例4
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8"/>
- <title>样例4</title>
- </head>
- <body>
- <input type="button" id="XSS" value="XSS"/>
- <script type = "text/javascript" >
- var btn = document.getElementById('XSS');
- btn.onclick = function() {
- document.write('<img src=@ onerror=alert(1234) />');
- // document.write('<img src=@ onerror=alert(1234) />');
- }
- </script>
- </body>
- </html>
运行结果:弹出-1234。
执行注释代码:页面输出字符串--<img src=@ onerror=alert(1234) />。(chorme下没有>输出,应该进行过滤了)
结果分析
对比样例1和样例2可以看出,当HTML代码段不被编码时,页面写入的是一个IMG标签,点击后会触发弹出框;而被编码后再写入页面时,展现的是标签的字符串形式,并没有被当成img DOM渲染。
那对比样例2和样例3 的执行结果,从二者document.write写入页面的字符串('<img src=@ onerror=alert(1234) />')来说是相同的,但为什么会有不同的执行结果呢?两个实例唯一的区别就是样例3的写入代码是完全的<input>标签内部,而样例2的写入代码先由<script>内的HtmlEncode编码后再写入。样例3中onclick里的这段JavaScript代码出现在HTML中,在浏览器载入后,浏览器会对其自动解码,所以在JavaScript执行前所要写入的字符串已经是‘<img src=@ onerror=alert(1234) />’,所以点击后会有弹出框。所以,样例1和样例3执行结果相同。
再看样例4,直接执行和执行注释部分二者有不同的结果,执行注释部分代码,里面的'<img src=@ onerror=alert(1234) />'会在JS执行前自动解码吗?根据其不同的执行结果,很明显是不会自动解码的,当用户输入的字符上下文环境是JavaScript,不是HTML(可以认为<script>标签里的内容和HTML环境毫无关系)时,这段内容需要遵循JavaScript规则。
为了防止XSS攻击,对于需要在JavaScript处理的字符,JavaScript也会其进行编码,有以下几种形式:
- Unicode形式:\uH(十六进制);
- 普通十六进制:\xH。
- 纯转义:\',\",\<,\>这样在特殊字符前加上\进行转义。
如果在样例4中写入的字符串按照JavaScript编码规则转义为--'\<img src\=@ onerror=alert\(1234\) \/\>',执行代码结果依然是弹出“1234”,并不是输出字符串,这是因为在JS代码中的代码会在执行之前进行自动解码,自动去掉转义。即使进行Unicode和十六进制编码,在执行前仍然会自动解码。
如何进行编码?
在JavaScript中有三套编码/解码函数,分别为:
- escape/unescape;
- encodeURL/decodeURL;
- encodeURLComponent/decodeURLComponent;
它们都是将不安全不合法的Url字符转换为合法的Url字符表示,其中一个很大的区别就是它们编码的敏感字符集不同,对于下面的字符不会进行编码:
- escape:*/@+-._0-9a-zA-Z (69个),对0-255以外的unicode值进行编码输出格式为:%u**** (已经被W3C废弃);
- encodeURL:!#$&'()*+,/:;=?@-._~0-9a-zA-Z (82个),使用UTF-8对非ASCII字符进行编码,然后再进行百分号编码;
- encodeURLComponent:!'()*-._~0-9a-zA-Z (71个),使用UTF-8对非ASCII字符进行编码,然后再进行百分号编码。
为了更好的理解,写了一个函数来实现escape功能,代码如下:
- var escape = function(str) {
- var _a, _b;
- var _c = "";
- for (var i = 0; i < str.length; i++) {
- _a = str.charCodeAt(i);
- _b = _a < 255 ? "%" : "%u"; // u不可大写
- _b = _a < 16 ? "%0" : _b;
- _c += _b + _a.toString(16).toUpperCase();
- }
- return _c;
- }
escape函数是从Javascript 1.0的时候就存在了,其他两个函数是在Javascript 1.5才引入的。但是由于Javascript 1.5已经非常普及了,所以实际上使用encodeURI和encodeURIComponent并不会有什么兼容性问题。
5.Base64编码
Base64编码可用于在HTTP环境下传递较长的标识信息。例如,在Java Persistence系统Hibernate中,就采用了Base64来将一个较长的唯一标识符(一般为128-bit的UUID)编码为一个字符串,用作HTTP表单和HTTP GET URL中的参数。在其他应用程序中,也常常需要把二进制数据编码为适合放在URL(包括隐藏表单域)中的形式。此时,采用Base64编码不仅比较简短,同时也具有不可读性,即所编码的数据不会被人用肉眼所直接看到。
Base64编码要求把3个8位字节(3*8=24)转化为4个6位的字节(4*6=24),之后在6位的前面补两个0,形成8位一个字节的形式。 如果剩下的字符不足3个字节,则用0填充,输出字符使用'=',因此编码后输出的文本末尾可能会出现1或2个'='。
为了保证所输出的编码位可读字符,Base64制定了一个编码表,以便进行统一转换。编码表的大小为2^6=64,这也是Base64名称的由来。
Base64编码过程
以下是一个Base64编码过程举例:
- 初始字符:s 1 3;
- ascii表示:115 49 51;
- 2进制(8个一组,3组):01110011 00110001 00110011;
- 重新分组(6个一组,4组): 011100 110011 000100 110011;
- 由于计算机是按照byte存储的,也就是8位8位的存数,6位不够,两个高位自动补0;
- 二进制转换为: 00011100 00110011 00000100 00110011;
- 转换为十六进制:28 51 4 51;
- 根据Base64编码表可得: c z E z。
由上例可知,初始字符“s13”就被转换为了“czEz”,使需要传输的字符变得不可读,一定程度上增加了安全性。
从网上找了一段JavaScript实现Base64的代码,如下所示:
- var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- var base64DecodeChars = new Array(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
- 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1);
- function base64encode(str) {
- var returnVal, i, len;
- var c1, c2, c3;
- len = str.length;
- i = 0;
- returnVal = "";
- while (i < len) {
- c1 = str.charCodeAt(i++) & 0xff;
- if (i == len) {
- returnVal += base64EncodeChars.charAt(c1 >> 2);
- returnVal += base64EncodeChars.charAt((c1 & 0x3) << 4);
- returnVal += "==";
- break;
- }
- c2 = str.charCodeAt(i++);
- if (i == len) {
- returnVal += base64EncodeChars.charAt(c1 >> 2);
- returnVal += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
- returnVal += base64EncodeChars.charAt((c2 & 0xF) << 2);
- returnVal += "=";
- break;
- }
- c3 = str.charCodeAt(i++);
- returnVal += base64EncodeChars.charAt(c1 >> 2);
- returnVal += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
- returnVal += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6));
- returnVal += base64EncodeChars.charAt(c3 & 0x3F);
- }
- return returnVal;
- }
- function base64decode(str) {
- varc1, c2, c3, c4;
- vari, len, returnVal;
- len = str.length;
- i = 0;
- returnVal = "";
- while (i < len) {
- /*c1*/
- do {
- c1 = base64DecodeChars[str.charCodeAt(i++) & 0xff];
- } while (i < len && c1 == -1);
- if (c1 == -1) {
- break;
- }
- /*c2*/
- do {
- c2 = base64DecodeChars[str.charCodeAt(i++) & 0xff];
- } while (i < len && c2 == -1);
- if (c2 == -1) {
- break;
- }
- returnVal += String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4));
- /*c3*/
- do {
- c3 = str.charCodeAt(i++) & 0xff;
- if (c3 == 61) {
- return returnVal;
- }
- c3 = base64DecodeChars[c3];
- } while (i < len && c3 == -1);
- if (c3 == -1) {
- break;
- }
- returnVal += String.fromCharCode(((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2));
- /*c4*/
- do {
- c4 = str.charCodeAt(i++) & 0xff;
- if (c4 == 61) {
- return returnVal;
- }
- c4 = base64DecodeChars[c4];
- } while (i < len && c4 == -1);
- if (c4 == -1) {
- break;
- }
- returnVal += String.fromCharCode(((c3 & 0x03) << 6) | c4);
- }
- return returnVal;
- }
Base64编解码
结束语
由编码规则产生的安全漏洞有很多,作为开发者要详细了解不同编码规则,对潜在的安全问题有所防御。有很多黑客会根据不同浏览器编码特性及采用的编码规则,利用特定的编码方式可绕过安全防御,实现对网站的攻击。在《Web前端黑客技术揭秘》一书中有很多讲述,感兴趣的同学可以读一下。
参考文献:
WEB前端 [编码] 规则浅析的更多相关文章
- web前端编码规范
简要介绍 本文通过参考百度腾讯等前端编码规范(链接建文末),得出个人习惯的编码规范.个人编码规范采用在不影响可读性的情况下能省就省,尽量简洁,不需要就直接去掉. 最佳原则不管是个人编码规范还是团队编码 ...
- Web前端编码规范[转]
先插入一条广告,博主新开了一家淘宝店,经营自己纯手工做的发饰,新店开业,只为信誉!需要的亲们可以光顾一下!谢谢大家的支持!店名: 小鱼尼莫手工饰品店经营: 发饰.头花.发夹.耳环等(手工制作)网店: ...
- 谈Web前端安全编码
最近开发中涉及到有关输出正确的HTML标签这样的问题,正好对字符编码这块儿多看看,之前对这个方面认识的不深,思考的确实不够,如果下次再碰见类似的问题,若再次不少时间去调研的花,就得不偿失了. 就像正则 ...
- HTML编码规范 - (WEB前端命名规范)
HTML编码规范 (一)命名规则: 头:header 内容:content/container 尾:footer 导航:nav 侧栏:sidebar 栏目:column 页面外围控制整体布局宽度:wr ...
- 【编码题篇】收集整理来自网络上的一些常见的 经典前端、H5面试题 Web前端开发面试题
编写一个方法 求一个字符串的字节长度假设:一个英文字符占用一个字节,一个中文字符占用两个字节 function GetBytes(str){ var len = str.length; var byt ...
- web前端开发浅析
原文地址:http://www.cnblogs.com/babyzone2004/articles/1807381.html 摘 要:前端开发作为一项新的领域,经历的时间随然较短,却显示了强大的生命里 ...
- web前端对文件的引用规则
web前端一般常用文件 .html .css .js.但是当用css文件和html引入资源(比如图片)时,路径可能不相同.下面总结了几条. 使用相对路径引入规则: html或者js引入图片,按照htm ...
- Web前端安全之安全编码原则
随着Web和移动应用等的快速发展,越来越多的Web安全问题逐渐显示出来.一个网站或一个移动应用,如果没有做好相关的安全防范工作,不仅会造成用户信息.服务器或数据库信息的泄露,更可能会造成用户财产的损失 ...
- [转载]Web前端开发工程师编程能力飞升之路
[背景] 如果你是刚进入web前端研发领域,想试试这潭水有多深,看这篇文章吧:如果你是做了两三年web产品前端研发,迷茫找不着提高之路,看这篇文章吧:如果你是四五年的前端开发高手,没有难题能难得住你的 ...
随机推荐
- Reactor模式,或者叫反应器模式 - 为什么用多路io复用提供吞吐量
Reactor这个词译成汉语还真没有什么合适的,很多地方叫反应器模式,但更多好像就直接叫reactor模式了,其实我觉着叫应答者模式更好理解一些.通过了解,这个模式更像一个侍卫,一直在等待你的召唤,或 ...
- 理解 OAuth 2.0
理解OAuth 2.0 http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html 一.简介 OAuth是一个关于授权(authorization)的开 ...
- Activiti工作流的应用示例
1.新建流程模型 模型管理->模型工作区 点击"创建"后会立即跳转到"流程在线设计器"页面,请参考下一节 2.在线流程设计器 模型管理->模型工作区 ...
- 关于 DjangoUeditor 上传图片图片失败,csrf token missing or incorrect 的解决办法
Forbidden (CSRF token missing or incorrect.): /ueditor/controller/ [27/Jun/2017 23:49:25] "POST ...
- Cloudstack 虚拟机实例(四)
虚拟机实例 默认的模板并没有被下载 修改全局设置 secstorage.allowed.internal.sites 设置 ,二级存储ISO镜像和模板可以下载,IP网段 重启服务/etc/init. ...
- 51NOD 1445 变色DNA
1445 变色DNA 有一只特别的狼,它在每个夜晚会进行变色,研究发现它可以变成N种颜色之一,将这些颜色标号为0,1,2...N-1.研究发现这只狼的基因中存在一个变色矩阵,记为colormap,如果 ...
- P3007 [USACO11JAN]大陆议会The Continental Cowngress
P3007 [USACO11JAN]大陆议会The Continental Cowngress 题意: 给出 n 个法案, m 头牛的意见, 每头牛有两个表决 格式为 "支持或反对某法案&q ...
- bzoj千题计划135:bzoj1066: [SCOI2007]蜥蜴
http://www.lydsy.com/JudgeOnline/problem.php?id=1066 每个柱子拆成两个点 i<<1,i<<1|1,之间连流量为高度的边 如果 ...
- Spyder之Object Inspector组件
Spyder之Object Inspector组件 最新版的Spyder已经把它修改为Help组件了. Quick access to documentation is a must for ever ...
- CentOS Linux 7 安装教程
建立新的虚拟机 将CentOS 7 ISO文件插入到CD-Rom 启动虚拟机,F12选择启动方式为CD/DVD 选择Install CentOS Linux 7 加载安装必要文件 选择安装过程所显示的 ...