nodejs随记02
2015-10-08 10:22
549 查看
Basic认证
检查报文头中Authorization字段,由认证方式和加密值构成;
basic认证中,加密值为
username:password,然后进行
Base64编码构成;
获取username和password;
var auth = req.headers['authorization']; var encoded = auth.split(' ')[1]; //获取加密值 var decoded = new Buffer(encoded, 'base64').toString('utf-8').split(':'); //解密 var user = decoded[0]; var pass = decoded[1];
加密
var encode = function (username, password) { return new Buffer(username + ':' + password).toString('base64'); };
判断认证失败后应该返回401状态码;
res.setHeader('WWW-Authenticate', 'Basic realm="secure Area"'); res.writeHead(401);
这种认证方式几乎明文,一般只在https情况下使用;
获得req.body
通过报头transfer-encoding或
content-length判断请求有无带内容
return 'transfer-encoding' in req.headers || 'content-length' in req.headers;
报文内容处理
var buffers = []; req.on('data', function (chunk) { buffers.push(chunk); }); req.on('end', function () { req.body = Buffer.concat(buffers).toString(); });
内存限制
限制上传内容大小,超过限制停止接受数据并响应400状态码;
//通过content-length判断 var bytes = 20; var cLength = req.headers['content-length']; var len = cLength ? parseInt(cLength, 10) : null; if (len && len > bytes) {} //在接受数据时判断 var received = 0; req.on('data', function (chunk) { received += chunk.length; if(received > bytes) { //停止接受数据,触发end(); req.destroy(); } });
设置缓存
判断if-modified-since
字段
fs.stat(path, callback): 获取文件信息
stat.mtime.toUTCString() === req.headers['if-modified-since']
相等的话响应304状态码
否则返回文件并重新设置
var lastModified = stat.mtime.toUTCString(); res.setHeader('Last-Modified', lastModified);
缺陷
文件时间戳改变但内容并不一定改动;
时间戳只精确到秒;
使用ETag
与If-Modified-Since/Last-Modified不同,它的请求是
If-None-Match/ETag
比较文件加密后的hash值和
if-none-match
//获取hash值 var getHash = function (str) { var shasum = crypto.createHash('sha1'); return shasum.update(str).digest('base64'); }; ..... var hash = getHash(file); //修改文件后hash值回改变 var noneMatch = req.headers['if-none-match']; if (hash === noneMatch) { res.writeHead(304, 'Not Modified'); res.end(); } else { res.setHeader('ETag', hash); res.writeHead(200, 'ok'); res.end(file); }
Expires和Cache-Control头
前面两个方法都还是需要发起一个条件请求Expires
是一个CMT格式的时间字符串;
其缺陷在于浏览器和服务器之间时间可能会不一样;
var expiresTime = 1000 * 60; var expires = new Date(); .... expires.setTime(expires.getTime() + expiresTime); res.setHeader('Expires', expires.toUTCString());
Cache-Control
采用倒计时的方法;
由于HTTP1.0不支持,一般多同时使用expires和cache-control;
若浏览器中同时存在且支持两个值,max-age会覆盖expires;
var cacheTime = 1000 * 60 * 60; .... res.setHeader('Cache-Control', 'max-age=' + cacheTime);
清除缓存
路径中跟随应用版本号:http://url.com/?v=20150618;
路径中跟随文件内容hash值:
http://url.com/?hash=adddfgg;
一般使用hash更高效;
cookie和session
对象化cookie
function parseCookie (cookie) { var cookies = {}; if(!cookie) return cookies; var list = cookie.split(';'); for(var i = 0, len = list.length; i < len; i++) { var pair = list[i].split('='); cookies[pair[0].trim()] = pair[1]; } return cookies; };
序列化(字符串化)
cookie
function serializeCoolie (name, val, opt) { var pairs = [name + '=' + encodeURIComponent(val)]; opt = opt || {}; if (opt.maxAge) pairs.push('Max-Age=' + opt.maxAge); if (opt.domain) pairs.push('Domain=' + opt.domain); if (opt.expires) pairs.push('Expires=' + opt.expires.toUTCString()); if (opt.httpOnly) pairs.push('httpOnly'); if (opt.secure) pairs.push('Secure'); return pairs.join('; '); };
例子
http.createServer(function (req, res) { req.cookies = parseCookie(req.headers.cookie); var num = req.cookies.num || 0; num = Number(num) + 1; if(!req.cookies.isVisit) { res.setHeader('Set-Cookie', [ serializeCoolie('isVisit', '1', {maxAge: 10}), serializeCoolie('num', num) ]); res.writeHead(200); res.write(num + ' ;'); res.end('first visit!'); } else { res.setHeader('Set-Cookie', serializeCoolie('num', num)); res.writeHead(200); res.write(num + ' ;'); res.end('welcome again!'); } }).listen(3000);
加密(crypto)
介绍: 提供了加密、解密、签名、验证等功能,利用OpenSSL库来实现加密技术Hash算法:
哈希算法,将任意长度的二进制值映射为较短的固定长度的二进制值; 一般对登陆密码,都是使用Hash算法进行加密;类型:
md5
sha
sha1
sha512
.....
crypto.createHash(algorithm);
hash.update(data, [input_encoding])
更新创建的hash内容;
对字符串,
input_encoding可以是
utf8,
ascii,
binary,默认
binary, 如果是
buffer则忽略;
hash.digest([encoding])
计算出hash值;
encoding可以是
hex,
binary,
base64,这时返回字符串;不设
encoding返回
buffer;
注意执行之后就必须重新
update值;
//hash:md5 var md5 = crypto.createHash('md5'); md5.update('foo'); md5.update('bar'); md5.digest('hex'); //hash:sha var sha1 = crypto.createHash('sha1'); sha1.update('foobar'); sha1.digest('hex');
Hmac算法:
利用哈希算法,以一个密钥和一个消息为输入,生成一个消息摘要作为输出生成 key.pen:
openssl genrsa -out key.pem 1024;
crypto.createHmac(algorithm, key)
加密和解密
对于有安全性要求的数据来说,需要加密存储,然后解密使用的,这时需要可逆的加密算法。对称加密算法: 一方用KEK加密明文,另一方收到后用同样的KEY来解密。
不对称加密算法: 使用完全不同但又是完全匹配的公钥和私钥。
c4和
aes-256-cbc加密和解密时间都比较短; 如果业务上,解密次数远大于加密次数,最好找到,加密时间:解密时间=N:1,N>1的算法;反之,那么
aes-256-cbc算法的计算时间比例就非常适合。
var crypto = require('crypto'); var fs = require('fs'); //加密解密算法 //加密 function cipher(algorithm, key, buf ,cb){ var encrypted = ""; var cip = crypto.createCipher(algorithm, key); encrypted += cip.update(buf, 'binary', 'hex'); encrypted += cip.final('hex'); cb(encrypted); }; //解密 function decipher(algorithm, key, encrypted,cb){ var decrypted = ""; var decipher = crypto.createDecipher(algorithm, key); decrypted += decipher.update(encrypted, 'hex', 'binary'); decrypted += decipher.final('binary'); cb(decrypted); }; function cipherDecipherFile(filename, algorithm, key){ fs.readFile(filename, "utf-8",function (err, data) { if (err) throw err; var s1 = new Date(); cipher(algorithm, key,data,function(encrypted){ var s2 = new Date(); console.log('加密算法:' + algorithm + ',' + (s2 - s1) + 'ms'); decipher(algorithm, key,encrypted,function(txt){ var s3 = new Date(); console.log('解密算法:' + algorithm + ',' + (s3 - s2) + 'ms'); }); }); }); }; var algs = ['blowfish','aes-256-cbc','cast','des','des3','idea','rc2','rc4','seed']; //常用加密解密算法 var key = "abc"; var filename = "readme.md"; algs.forEach(function(name){ cipherDecipherFile(filename,name,key); });
签名和验证
除了对数据加密和解密,还需要判断数据在传输过程中,是否被篡改了。就需要用到签名和验证的算法,利用不对称加密算法,通过私钥进行数字签名,公钥验证数据的真实性。生成私钥:
openssl genrsa -out server.pem 1024
生成公钥:
openssl req -key server.pem -new -x509 -out cert.pem
var crypto = require('crypto'); var fs = require('fs'); //签名验证算法 function signer(algorithm,key,data){ var sign = crypto.createSign(algorithm); sign.update(data); sig = sign.sign(key, 'hex'); return sig; } function verify(algorithm,pub,sig,data){ var verify = crypto.createVerify(algorithm); verify.update(data); return verify.verify(pubkey, sig, 'hex') } var algorithm = 'RSA-SHA256'; var data = "abcdef"; //传输的数据 var privatePem = fs.readFileSync('server.pem'); var key = privatePem.toString(); var sig = signer(algorithm,key,data); //数字签名 var publicPem = fs.readFileSync('cert.pem'); var pubkey = publicPem.toString(); console.log(verify(algorithm,pubkey,sig,data)); //验证数据,通过公钥、数字签名 =》是原始数据 console.log(verify(algorithm,pubkey,sig,data + "2")); //验证数据,通过公钥、数字签名 =》不是原始数据
salt算法
密码任意固定位置插入特定的字符串,让散列后的结果和使用原始密码的散列结果不相符;var crypto = require('crypto'); //salt算法 var md5 = crypto.createHash('md5'); var txt = "123465"; md5.update(txt); console.log(md5.digest('hex')); md5 = crypto.createHash('md5'); var salt = "abcdefghijklmnopqrstuvwxyz"; md5.update(txt + salt); console.log(md5.digest('hex')); //使用crypto.pbkdf2()函数取代手动加盐,默认会调用hmac算法 var txt = "123465"; var salt = "abcdefghijklmnopqrstuvwxyz"; // 生成密文,默认HMAC函数是sha1算法, 生成256位的密文 crypto.pbkdf2(txt, salt, 4096, 256, function (err,hash) { if (err) { throw err; } console.log(hash.toString('hex')); }); //利用随机randomBytes()函数,配合pbkdf2()函数,让每次都是不同的salt crypto.randomBytes(128, function (err, salt) { if (err) { throw err;} salt = salt.toString('hex'); console.log(salt); //生成salt crypto.pbkdf2(txt, salt, 4096, 256, function (err,hash) { if (err) { throw err; } hash = hash.toString('hex'); console.log(hash);//生成密文 }) });
相关文章推荐
- Node.js学习总结(一)
- Node.js开发入门—Buffer用法详解
- nodejs 设置API代理
- node.js 使用 UglifyJS2 高效率压缩 javascript 文件
- node.js提示req.body为undefined
- node lesson3
- nodejs是单线程
- node lesson2
- Windows环境下的NodeJS+NPM+Bower安装配置步骤
- 省时的浏览器同步测试工具 browsersync NodeJS
- VPS 运行 Node.js 的一些经验
- *LeetCode-Populating Next Right Pointers in Each Node II
- Nodejs安装
- node.js处理torrent
- node.js 在 Express4.0 框架使用 Connect-Busboy 实现文件上传
- Node.JS学习笔记: 基础篇
- Hadoop ->> Name node/Data node和Job tracker/Task tracker的区别
- 初识Node.js
- Hadoop动态加入/删除节点(datanode和tacktracker)
- 为什么我要用 Node.js? 案例逐一介绍