nodejs随记02
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);//生成密文
})
});
nodejs随记02的更多相关文章
- nodejs学习总结02
response对象常用的API #response对象 response 对象类型<http.ServerResponse> response对象常用成员:response.write ...
- 【NodeJS 学习笔记02】入门资源很重要
前言 在我映像中,异步最早出现与ajax,当时我还在搞.net,然后.net居然出了一个异步的控件...... 虽然我最后知道了他不是异步的......然后,前端异步用得特别多,如果不是异步的程序,你 ...
- Angular4+NodeJs+MySQL 入门-02 MySql操作类
NodeJs操作MySQL类 此类封装了几个常用的方法:插入,更新,删除,查询,开启事务,事务提交,事务回滚等操作.有一这个类,操作MYSQL就方便多了. 批处理,存储过程等方法还没有添加,因为觉得目 ...
- 【Nodejs】记一次图像识别的冒险
笔者的团队最近接到了一个有关图像识别的需求,本来应该由后端团队提供能力,native提供容器,前端团队仅负责一些“外围的形式工作”,不过由于各种各样的原因,最后的结果变成了前端团队在原有工作基础上,承 ...
- nodejs随记04
aes加密 资料 简介; 例子; process 改变工作目录: process.chdir(path); 路径计算 例子 获取调用执行所在文件地址 function getCaller() { tr ...
- css随记02布局
布局 二栏布局 利用absolute, margin .container { position: relative; } nav { position: absolute; left: 0px; w ...
- nodejs随记03
文件操作 文件系统的操作 fs.readFile(filename, [options], callback) fs.writeFile(filename, data, [options], call ...
- nodejs随记01
EventEmitter var stream = require('stream'); var Readable = stream.Readable; //写入类(http-req就是),初始化时会 ...
- tensorflow-笔记02
TensorFlow扩展功能 自动求导.子图的执行.计算图控制流.队列/容器 1.TensorFlow自动求导 在深度学习乃至机器学习中,计算损失函数的梯度是最基本的需求,因此TensorFlow也原 ...
随机推荐
- IOS-KVO&KVC
KVC(key value coding) 我们一般是通过调用set方法或属性的点语法来直接更改对象的状态,即对象的属性值,比如[stu setAge:10]; stu.age = 9; lKVC, ...
- Ubuntu离线更新flashplugin
当网络太烂时,Ubuntu更新可能会卡在下载flashplugin上面,继而出错.在U论坛上找到一篇帖子,寻到成功安装flashplugin-installer的方法: 1.首先使用sudo apt- ...
- poj1417(种类并查集+dp)
题目:http://poj.org/problem?id=1417 题意:输入三个数m, p, q 分别表示接下来的输入行数,天使数目,恶魔数目: 接下来m行输入形如x, y, ch,ch为yes表示 ...
- NYOJ题目111分数加减法
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAsEAAAKBCAIAAAA5i+FPAAAgAElEQVR4nO3dPXLbugMv7LsJ916Iay ...
- eclipse查看hadoop中文件出现乱码
出现这个问题, 我首先去找了一下几个问题: 1.文件是否是utf-8 2.上传到Linux中的hadoop, 在Linux下去查看是否乱码 3.上面都没有问题, 就去检查eclipse,将项目工程改成 ...
- .netWeb方向:语言+技术
常用语言+技术 C# T-Sql ADO.NEt JavaScript Asp.Net MVC HTML CSS DOM AJAX Entity Framework Regular expressio ...
- pyinstaller打包pyqt文件
打包pyqt文件 如何将pyqt生成exe的二进制文件呢,pyinstaller就是这样的工具 可以将脚本文件.py 文件转换为编辑后的二进制文件,在进行发布 下面说下,如果打包 一. 安装: 下载地 ...
- C# TreeView使用技巧
节点勾选设置 TreeView树中节点勾选要求: 1.不选中一个节点,则其所有的子节点都不被选中. 2.选中一个节点,则其所有的子节点都被选中. 3.当一个节点的所有子节点都没有被选中时,该节点也没有 ...
- Analysis Services OLAP 概述
1. 什么是OLAP •定义1 :OLAP(联机分析处理)是针对特定问题的联机数据访问和分析.通过对信息(维数据)的多种可能的观察形式进行快速.稳定一致和交互性的存取,允许管理决策人员对数据进行深入观 ...
- 5-06使用Sql 语句为表添加约束
约束名的命名规则推荐采用:约束类型_约束列. 为用户表添加约束 ALTER TABLE UserInfo ADD CONSTRALNT PK_UserId PRIMATY REY(UserId) CO ...