May 10, 2012

入手yubikey,一点小心得

昨天从 @yeagle 那里买的 yubikey 终于到货,如果不知道 yubikey 是什么就看看 @yeagle 的广告好了,呵呵。

去年 CSDN 事件现在还令人心有余悸,再加上早年安全意识不足,多个网站都是一套密码,想起来实在后怕,于是立马开始用 Lastpass,给大部份网站都换成随机密码, Google 帐户开两步认证,免得被 Big Brother 翻邮箱什么的。

但是 Google Authenticator 还是太不方便,登录的时候麻烦不少,需要敲完密码再摸出手机打开App然后再敲一遍 verify code,敲慢了还会过期还要再敲一遍,实在是影响 用户体验

另一方面,在不少场合下,公然敲密码都是一件比较尴尬的事情,怕别人看到,又不好意思遮遮掩掩什么的,所以只有锻炼手速,然而手速快了又容易敲错,噗呵呵… 还有的时候电脑需要给人用一下,但是又不方便告诉他密码什么的,这就很头疼。这两种情况之前我都是用 pam_usb 解决的,把优盘搞成钥匙用,但是安全性就比较差了。

所以我就买了yubikey,廉价的一次一密方案。

其实主要想写的是 pam_yubico, PAM 是Linux中的用户认证机制, pam_yubico 故名思义就是用 yubikey 进行 Linux 用户认证,login啊 unlock screeen啊,ssh啊什么的。 Arch的 AUR 里已经有了,别的系统自己打个包也不麻烦,不过比较令我奇怪的是从 github 里 clone 下来的代码在运行 automake 的时候竟然会报错说 libykclient.la 不是符合 POSIX 要求的库……没办法只好下载 release 版了。

根据 pam_yubico 的手册,在 /etc/pam.d/sudo /*这里注释一下,不同发型版PAM的配置不太一样,例如 debian 就提供了一个 common-auth,只要改一个就好了, arch 就要一个一个改,或者把PAM配置文件结构改成debian那样…… */的最上面一行加入

auth    sufficient  pam_yubico.so id=16

然后建立 ~/.yubico/authorized_yubikeys,文件格式是

username:xxxxooxxoxoxoxoxox

其中 username 当然是你的用户名啦, xxxxooxxoxoxoxoxox 是 yubikey 的 ID,简单的说就是按下yubikey后那一长串字符的前12个。

于是你现在可以 sudo 一下试试,提示输入 yubikey password,按一下 yubikey 就认证成功了。

话说如果想用 yubikey 加强安全,要同时有 yubikey 和系统密码才能登录的话就把 sufficient 改成 required 就好。

但是这种办法有一个 bug,就是只能在线使用,pam_yubico 会在得到 yubikey password 后提交给 yubico 的认证服务器进行认证,这就让灵活性大打折扣了,在天朝这种地方,老大哥说不定哪天就不让你能连上万恶的资本主义国家的互联网了呢。

解决办法有两个,

  1. 自己搭建 yubikey 认证服务: yubikey 是从硬件到软件到服务全部开源的良心产品,所以自己搭建一个本地 yubikey 认证服务就可以,搞定离线问题
  2. 使用 Challenge-response 模式

自己搭建yubikey认证服务还是麻烦了些,而且弄完之后yubikey就不能再用于公开的认证了,代价太高了些,所以我选第二种方案,challenge-response模式,原理我也没弄明白,基本就是本地生成个密钥,然后跟 yubikey 里存储的另一串密钥对一下,对上就算成功,跟传统的yubikey认证是不太一样的。

具体怎么做, 给 pam_yubico 加个mode=challenge-response 就好,具体看 man ykpamcfg 里面写得足够详细了。

但是配完之后发现 sudo 运行良好但是 gdm 却无法使用 challenge-response 模式,看/var/log/auth.log 发现原来是权限不够,于是给 yubikey 的 usbbus 直接改成 777 果然就好了,但是这太 dirty 了,想想能不能通过 udev 的 rules 写一条,类似于

SUBSYSTEM=={usb}, ATTR{idVendor}=={00XX}, ATTR{idProduct}={00XX}, MODE="0666" 

之类的,搞了半天发现不管用, google 之,果然发现其实 yubico 在 Github 的代码里已经有了 udev 规则了,在 /etc/udev/rules.d 里加一个 yubikey.rules

ACTION=="add|change", SUBSYSTEM=="usb", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0010", TEST=="/var/run/ConsoleKit/database", RUN+="udev-acl --action=$env{ACTION} --device=$env{DEVNAME}"

就好。看起来使用了ConsoleKit,Linux的权限配置还是真够麻烦。/*写到这里突然想起来Linus年初喷OpenSUSE连无线网络要root密码的事情了2333*/

累了,就写到这里吧。 /* 看起来好像我更新博客速度好慢,其实最近学到很多东西都想写下来,可惜 太懒 还有更重要的事情要做,好了我会积极更新的。 */

© Justin Wong 2017