首页 > 安全 > 网络安全 >

动手打造跨设备、无需同步的密码管理器

2016-12-20

动手打造跨设备、无需同步的密码管理器。密码管理器大家都有用过吧?但你相信有一种密码管理器不仅可以跨设备使用,还无需同步!无论你相不相信,今天就让我来教你如何自己动手制作一个。

动手打造跨设备、无需同步的密码管理器。密码管理器大家都有用过吧?但你相信有一种密码管理器不仅可以跨设备使用,还无需同步!无论你相不相信,今天就让我来教你如何自己动手制作一个。

密码管理器,实在太多。简直能让人挑花眼。有各种各样类型的,但主要是有2种:网络同步的、存在自己本地数据库的。从理论上讲,存在本地的会比自己存在网络上的会相对安全一点。因为最近经常能听到某些网络型密码管理器被爆出漏洞什么的,虽然说你保存的密码是加密保存在服务器上的,但还是有点安全隐患。

相对于网络型密码管理器,本地型密码管理器确实会安全一点(取决与你的安全意识)。不过,与此同时,也带来一些缺点。比如没有网络型的方便,需自己对保存密码的数据库进行同步等等。

原理说明

跨平台?离线?不同步?

如果要实现这3个要求,我们需要重新审视一下自己对应密码管理器的需求。首先,我们使用密码管理器的目的不仅仅是为了保存密码,还为了安全。保证每个网站注册的密码都不同,而且是随机的,不存在与本人有挂钩的信息,比如手机号、生日、幸运数字等等,防止他人根据你的个人信息生成字典跑包。

既然要保证密码中没有个人信息,而且需要无序,随机数显然是最好的选择。但如果使用随机数就无法实现每个平台都相同。所以必须使用一个统一的算法,这样各个设备使用同一套算法就能保证生成的密码都是相同的。

最终,想到如下算法,来实现密码同步:

用户需指定一个通用密码

需要指定一个网站的域名(不包含具体文件地址)

使用Hash算法生成密码。

这样,我们就能保证各个网站的密码都不一样,而且还不需要同步!

开始动手

密码管理器最终还是为浏览器服务的,不如我们直接将它做成Chrome浏览器扩展,这样使用方便,还能跨平台。

chrome扩展开发

开发一个chrome扩展其实很简单,只需要一点js的知识就行了,接下来让我们一起来看看如何开发!

要开发,首先需要开发者文档,这是Google官方的文档地址,请自备梯子。如果需要中文文档的话可以自己找翻译版本的~

第一,在本地新建一个文件夹,这里取名为“ImPassword”

\

第二,新建一个名称为manifest.json 的文件,这是用于保存整个扩展的描述信息。

{

"manifest_version": 2,

"name": "扩展名称",

"description": "扩展描述文件",

"version": "版本号",

"browser_action": {

"default_icon": "默认图标",

"default_popup": "点击弹出的HTML网页"

},

"permissions": [

"权限信息"

]

}

第三,我们再来分析一下。我们这个扩展的需求。

1.扩展要能提取到浏览器地址栏的网址。

2.能储存必要的信息到本地中。

3.对所有的网站都必须要有读取的权限。

第四,根据需求,我们查查开发者文档,需要加入一些权限,比如:"permissions": ["tabs","storage",""]

第五,把最终的manifest.json 文件写出来!

{

"name": "密码管理器",

"manifest_version":2,

"version": "1.0",

"description": "密码管理器Chrome扩展",

"permissions": [

"tabs",

"storage",

""

],

"options_page": "options.html",

"browser_action": {

"default_icon": "icon.png",

"default_popup": "popup.html"

},

"background" : {

"scripts" : [

"bg.js"

]

}

}

这里简单的对上面的信息解析说明。permissions表示你需要申请的权限。options_page表示“选项”界面和html网页,也就是说,有了这个字段则当扩展安装到浏览器后,能实现 右键->选项 操作。background里的内容我这里是添加一个空js文件,因为如果没有该参数,每次点开扩展的时候鼠标会一直转转转,强迫症患者表示无法接受。

第六,根据信息,建立相关的文件。

\

书写代码

从用户的角度看,用户点击一下我们的扩展图标会弹出一个小小的框框,而这个框实际上就是我们上面配置的popup.html。使用这个html文件里的内容就是用户能看到的东西,可以称它为显示界面。

options 代码

对于options.html内的内容则是当用户右键->选项时显示的内容。我们现在的目的就是,通过选项界面需要用户配置一个独立密钥,并保存。而当用户点击扩展图标的时候,扩展会自动获取网站的域名,并与设置的密钥进行Hash操作,产生一个重复率比较低的网站密码。

首先,打开popup.html文件,写入以下内容

html>

body>

p id="status">

hello

p>

body>

script type="text/javascript" src="/md5.js">script>

script type="text/javascript" charset="utf-8" src="/popup.js">script>

html>

这里的代码实在太简单了,相信大家都能看懂。id为status的标签主要用来显示网站的密码,下面引用了2个JS文件,一个是我们等一下要写的popup.js文件,还有一个是用于哈希的库。

由于考虑到很多网站的密码位数不能大于20位,大部分的hash函数都无法用,这里只能用一个16 BIT MD5的hash算法。

现在,先来写一下选项界面的代码。

打开options.html,写入以下内容。

html>

head>title>选项title>head>

body>

div>输入密码:

input type="text" id="text">input>

button id="set">保存button>

div>

script src="options.js">script>

body>

html>

其实也就是一个简单的html,一个文本框一个按钮而且。接下来打开options.js,开始真正写代码了。

document.body.onload = function() {

chrome.storage.sync.get("data", function(items) {

if (items.data == undefined){

return;

}

if (!chrome.runtime.error) {

console.log(items);

document.getElementById("text").value = items.data;

}

});

}

document.getElementById("set").onclick = function() {

var d = document.getElementById("text").value;

chrome.storage.sync.set({ "data" : d }, function() {

if (chrome.runtime.error) {

console.log("Runtime error.");

}

});

window.close();

}

下面来和分析一下,上面代码的具体意思。代码由2个块组成,这2个块实际上都是事件。第一个为载入事件(即当你打开选项界面的时候会触发的内容),第二个为ID为set的按钮的点击事件。

chrome.storage.sync.get是chrome的一个api,用于获取储存的内容。这里的判断逻辑是,如果获取有获取到内容(即说明之前有保存过密码),则显示原先的密码。如果没有获取到,就不显示。

chrome.storage.sync.set就很好理解了,当然是把密码保存起来起来。

popup 代码

既然选项界面的代码写好了,接下来看看popup.js里的内容,这个是这个扩展的主要逻辑部分。但也不要担心,这个扩展只是做了一点微小的工作,不会很难~

看看popup.js的全部代码,等一下我们再来分析具体的原理。

var receiver_data = new Array(), callFun;

chrome.tabs.query({'active': true, 'windowId': chrome.windows.WINDOW_ID_CURRENT},

function(tabs){

var urlLink = tabs[0].url.replace("http://", '').replace("https://", '').split('/')[0];

chrome.storage.sync.get("data", function(items) {

if(items.data == undefined){

document.getElementById('status').textContent = "未配置独立密钥!";

return;

}

if (!chrome.runtime.error) {

pass = items.data;

receiver(["Password",pass]); //发送信号

}

});

receiver(["Url",urlLink]);

receiver(["RUN",run]);//发送函数信号

}

);

function receiver(value){ //信号接受函数

if(value[0] == "RUN"){

callFun = value[1];

return 0;

}

if(receiver_data.length >= 2){//清空

receiver_data.length = 0;

receiver_data.push(value);

return 0;

}

if(receiver_data.length 2){//继续添加

receiver_data.push(value);

}

if(typeof(callFun)=="function" && receiver_data.length == 2){

callFun(receiver_data);

}

}

function run(buf){

if(buf.length == 2){

var pass,urlad;

if(buf[0][0] == "Url"){

urlad = buf[0][1];

pass = buf[1][1];

}else{

pass = buf[0][1];

urlad = buf[1][1];

}

document.getElementById('status').textContent = (urlad.MD5()+pass.MD5()).MD5();

}

}

开头定义了2个全局变量,一个是接收器数组,一个是储存函数指针的变量。

由于Chrome是以回调的方式返回具体的url的,这样会给我们处理带来很大不便。所以receiver是我自己定义的一个接收器,用于处理传入的信号,并将信号数据保存到接收器数组里。接收器数组就像一个容器,接受到的数据只要不超过数组下标,均保存起来。接收器会对传入的信号进行处理,如果没出现Run标志,则把数据保存到数组中,如果出现指定标志,则通过函数指针执行指定函数,同时带上接收器数组的内容。

介绍完接收器的具体实现方式,我们再来看看,这个代码的具体逻辑。

由于我们需要得到tab的URL地址,并对其进行分解。所以要使用Chrome的一个api去实现(前面我们已经申请了权限)。

chrome.tabs.query({'active': true, 'windowId': chrome.windows.WINDOW_ID_CURRENT},function(tabs){})

现在只需要在function(tabs){}内写入需要执行的操作即可!而该匿名函数内的处理的是,对tabs得到的url地址进行分解,得到一个域名地址,并保存到urllink中。接着从chrome.storage取到之前保存的密钥,如果没有则显示“未配置密钥”。然后就是把密码、地址、run函数指针,通通发送给receiver.

receiver判断传入的标签,如果是RUN则将函数指针保存到callFun变量中,如果是其他的则保存到receiver_data数组里。

run函数主要是处理由receiver传的参数,并对参数解析。最终进行Hash计算并输出到ID为status的标签中。

总结

虽然说,这里使用的密码是用md5 16bit 计算出来的,但也确实是无奈之举,同时也不算太安全。但相对与N个网站用同一个密码来说,这套不需要同步的且N个网站对应N个密码的方案,确实能有效的提高安全性。不过,这套方案真的有那么完美吗?显然不是。举个例子,你无法很高效更改某个网站的密码。假设有一天你注册过的某个网站被脱裤,你的密码被爆出来了,虽然不会影响其他网站账号,但你在该网站的密码肯定要修改吧?但你没有一个很有效的方案修改密码,因为该密码是根据你的初始密钥计算出来的,如果要修改就要修改初始密钥,那就得修改所有网站的密码……

没办法,一个方案有它好的方面,必然有它不好的方面。所以我本人的解决方案是,用2种密码管理器,一种是本地型的,一种是本篇文章写的。我对于一些很重要的网站,比如支付宝、百度、Google、Youtube、Twitter、Freebuf、Github…这些网站均保存到本地密码管理器中,而在网络中其他乱七八糟的网站、或者是各种只有注册才能看的网站,都用本篇文章的密码管理器生成密码。对于重点网站重点保护,对于不重要的网站用普通的方式保存(但安全性也蛮高的)。

根据开发者文档的描述,用chrome.storage保存密码的方式貌似并不安全,欢迎大家提供更好的方式给我~

最后,我把该扩展的所有代码,打包上传到Github上了,欢迎大家提交issues和pull request哦!

相关文章
最新文章
热点推荐