雙因素認證 Two-Factor Authentication(2FA)

avatar 2020年1月7日18:46:20雙因素認證 Two-Factor Authentication(2FA)已关闭评论

用於身份認證授權(Authentication)主要有三方面要素:

1)用戶所知,密碼或者身份證號碼
2)用戶所有,手機或者USB Key、磁卡
3)用戶本身的特徵,指紋、瞳孔、聲音

單獨來看,每個要素獨立存在時,都有其脆弱性。雙要素認證就是結合兩種要素,實現有效提高系統訪問(如,登入)或控制(如,轉帳)的安全性。

雙因素認證或雙重驗證(Two-Factor Authentication,2FA)是多因素身份驗證的子集類型之一。是採用證因素中的兩項組合來做身分驗證的方法。

雙因素認證的例子,

【例】從ATM取款。需要以提款卡(用戶所有)加上密碼(用戶所知)的正確組合才能進行交易。

【例】透過用戶所持有,如:認證過的手機上的SMS或安裝的驗證器APP,所生成或接收的一次性密碼(OTP),以(用戶所有的手機)收到之SMS或OTP,搭配(用戶所知)帳號密碼,兩者的正確組合來實現雙因素認證,加強身份認證授權(Authentication)的安全性。

Google Authenticator(谷歌驗證器,GA)

GA使用的一次性密碼(One Time Password,簡稱 OTP)算法,應用基於時間的TOTP(RFC 6238)和基於HMAC訊息認證碼的一次性密碼算法(HOTP;RFC 4226)。GA以時間戳記每30秒產生一組六位數的一次性密碼,實現雙因素驗證的服務,提高帳戶的安全性,也是目前最常採用的雙因素驗證方法。

【實現】

實現Google Authenticator功能需要伺服器端和客戶端的支援。
伺服器端負責金鑰的生成、驗證一次性密碼是否正確。客戶端記錄金鑰後生成一次性密碼。

一、安裝GA服務時:
1.伺服器隨機生成一個與客戶端共享的秘密金鑰(Shared Screte Key),並把秘密金鑰儲存到伺服器資料庫。如:DPI45HKISEXU6HG7
2.在申請GA的頁面上顯示秘密金鑰的二維碼(以方便客戶端的輸入)。內容為URI地址(otpauth://totp/賬號?secret=金鑰)。如:otpauth://totp/[email protected]?secret=DPI45HCEBCJK6HG7
3.客戶端GA APP掃描二維碼,將秘密金鑰儲存在客戶端APP。

二、使用GA驗證時:
1.客戶端每30秒使用安裝的秘密金鑰和時間戳,生成一個6位數字的一次性密碼OTP。
2.使用者輸入當時的OTP做身分驗證。
3.伺服器端使用資料庫中的金鑰和時間戳通過同一種『演算法』生成一個6位數字的一次性密碼。

由於加解密演算法及運算方式是公開的,如果雙方的秘密金鑰相同,在限定時間內(每30秒內相同的時間戳)所產生的OTP會是一致的。當客戶端提交的OTP和伺服器計算出的是一樣的話,就通過驗證了。

Google Authenticator的運算原理

Google的兩步驗證演算法源自另一種名為HMAC-Based One-Time Password的演算法,簡稱HOTP。

HOTP的工作原理:
用戶端和伺服器事先協商好一個金鑰K,用於一次性密碼的生成過程,此金鑰不被第三者所知。
其次,用戶端和伺服器各有一個時間戳計數器C,且計數值要維持同步。【因此,注意】若使用 Google Authenticator作為2FA工具的話,則你系统(手機)的日期及時間必需正確,(在台灣)若您的手機不是中原標準時間,則會因為時戳不同而產生(與伺服器不同)無效的OTP。

進行驗證時,用戶端對金鑰和計數器的組合(K,C)使用HMAC(Hash-based Message Authentication Code)演算法計算一次性密碼,公式如下:

HOTP(K,C) = Truncate(HMAC-SHA-1(K,C))

上面採用了HMAC-SHA-1,當然也可以使用HMAC-MD5等。

HMAC演算法得出的值位元數比較多,不方便使用者輸入,因此需要截斷(Truncate)成較短的十進位數字OTP(例如6位)。
計算完成之後用戶端計數器C計數值加1。
用戶將這一組OTP輸入並且提交之後,伺服器端同樣的計算,並且與用戶提交的數值比較,如果相同,則驗證通過;如果不相同,則驗證失敗。

TOTP將HOTP中的計數器C用當前時間T來替代,於是就得到了隨著時間變化的一次性密碼。

雖然原理很簡單,但是用時間來替代計數器會有一些特殊的問題,我們選取幾個進行一下探討。

首先,時間T的值怎麼選取?時間太短,來不及輸入即時的OTP;時間太長,則增加安全疑慮。

時間長短取捨問題在:由於網路延遲,使用者輸入延遲等因素,若當伺服器端接收到OTP時,T的計數值已經改變時,將導致server端計算出的OTP值與使用者輸入的(前一次或更早的)OTP不同,而驗證失敗。

若Authenticator選了一個(太即時,太短)的T(如:幾秒鐘)做運算,則使用者會時間太短,來不及輸入即時的OTP,便已失效。再則,如果用戶端和伺服器的時鐘有誤差,而非完全同步,也會造成用戶端與伺服端生成OTP不一致。

相反的,若Authenticator選擇太長的T(如:幾小時);那麼攻擊者便有更充足的時間去嘗試所有可能的OTP(6位數位的OTP僅僅有10^6種組合),而降低了OTP的安全性。
除此之外,太長的T還會導致另一個問題。當使用者需要在短時間內,做兩次2FA時。由於OTP是一次性不可重用,那麼用戶必須等到下一個OTP再被生成時才做2FA驗證。這意味著必須要等待更長的時間間隔,才能進行下一次的2FA驗證。這也造成使用的不便。

綜合以上考慮,Google選擇了30秒作為時間切片。T的數值為從Unix epoch(1970年1月1日 00:00:00)後所經過的30秒的個數為counter記數值。

【使用上的考慮】該不該將裝置識別為「可信任的裝置」?
大多數雙因子認證的網站會在第一次使用2FA服務時,跳出一個訊息,詢問並允許用戶是否要「將裝置識別為可信任的裝置」?

如果你答應了,則此一受信任的裝置在未來便可以排除不再受限雙因素認證的安全要求,只要在該裝置上登入這個服務時,便不會再被要求進行2FA驗證。這固然方便,但也有一定的安全隱憂。如果你在受信任的裝置上關閉了雙因素認證,安全問題就會變成:你得自己保證你的裝置是一定安全的;包括不會遺失或被駭入或中毒(木馬程式等)。而且也要記得對信任的裝置清單進行維護(移除),尤其在裝置遺失的時候非常重要。

【出處】關於密碼的雙因素授權,你應該要知道的5 件事

雙因素認證- MBA智库百科

▲【新聞】(2019/3/8)利用SMS發送或使用驗證的雙因素認證(2FA)不再安全

波蘭研究人員公佈了一個名為Modlishka自動化執行釣魚攻擊工具,可破解利用SMS發送或使用驗證應用程式產生的一次性密碼(One Time Password,OTP)。

Modlishka的手法是利用釣魚網站,來截取使用者受欺騙後傳送的任何憑證與雙因子認證。就如同反向代理伺服器,可巧妙地提供使用者網路上的真實內容,使攻擊看起來更具說服力,而非僅複製登入畫面以蒙騙使用者(例如Gmail),並且讓使用者以為是真實網站的互動機制,事實上,Modlishka在使用者不知情之下背景記錄所有資訊。

網路上公開的影片(https://vimeo.com/308709275)清楚示範利用Modlishka攻擊手法,得以輕易地騙取Google使用者的驗證資訊。

該如何因應?

首先必須了解,OTP網路釣魚有其限制,如:OTP只有30秒有效時間。破解期間必須在有效時間攔截到OTP以免失效,並同時運用社交工程的手法,影響或誘騙目標使用者點選瀏覽釣魚網站。

從技術角度來看,此問題的唯一解決方法是:改用通用第二因素(Universal 2nd Factor,U2F)通訊協定的2FA實體金鑰。U2F可以從Yubico購買,也可向Google訂購Titan安全金鑰。最理想情況是購買並註冊兩種實體金鑰(一個是備份之用),費用大約50美元。

2019/3/8【出處】軟體及簡訊OTP雙因認證已被破解,2FA實體金鑰 保護帳密免遭竊

參考資料

  1. TOTP: Time-based One-time Password Algorithm, RFC Draft, http://tools.ietf.org/id/draft-mraihi-totp-timebased-06.html
  2. HOTP: An HMAC-Based One-Time Password Algorithm, RFC 4226, http://tools.ietf.org/html/rfc4226
  3. Google Authenticator project, http://code.google.com/p/google-authenticator/

【出處】https://blog.seetee.me/post/2011/google-two-step-verification/

【附錄,轉載自】(Article listed below original from) How Google Authenticator Works ?

Most people use Google Authenticator to generate two-factor authentication (2FA) tokens on their phone, with Authy as a recent alternative. What's cool is that any service can make use of these apps as long as it is compatible. But what does it mean to be compatible? How do these apps work?

Apps like Google Authenticator implement the Time-Based One-Time Password (TOTP) algorithm. It has the following ingredients:

  • shared secret (a sequence of bytes)
  • An input derived from the current time
  • signing function

Shared Secret

The shared secret is what you need to obtain to set up the account on your phone. Either you take a photo of a QR code using your phone or you can enter the secret manually. Because not all byte values are displayable characters the secret is base32-encoded (why not base64?).

For manual entry Google's services present this secret has the following format:

xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx

This value is 256 bits but can be smaller for other services. The QR code contains this same token as a URL:

otpauth://totp/Google%[email protected]?secret=xxxx&issuer=Google

Input (Current Time)

The input time value you'll simply get from your phone, no further interaction with the server is required once you have obtained the secret. However it is important that your phone's time is accurate as the server will essentially repeat what happens on your phone using the current time as known by the server.

More specifically the server will actually compare submitted tokens to all tokens generated for a window of time (e.g. a couple of minutes) to account for the time it takes for you to type the token and send it to the server.

Signing Function

The signing function used is HMAC-SHA1. HMAC stands for Hash-based message authentication code and it is an algorithm that uses a secure one-way hash function (SHA1 in this case) to sign a value. Using an HMAC allows us to verify authenticity - only people knowing the secret can generate the same output for the same input (the current time). This all sounds complex but the algorithm is very simple (details omitted):

hmac = SHA1(secret + SHA1(secret + input))

As an aside TOTP is in fact a superset of HOTP or HMAC-Based One-Time Password Algorithm - they are the same thing except that TOTP specifies that the current time is used as the input value while HOTP simply uses an incrementing counter that needs to be synchronized.

Algorithm

First we'll need to base32 decode the secret. Google presents it with spaces and in lowercase to make it easier to grok for humans, but base32 actually does not allow spaces and only allows uppercase letters. Thus:

original_secret = xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx secret = BASE32_DECODE(TO_UPPERCASE(REMOVE_SPACES(original_secret)))

Next we derive the input from the current time, for this we'll use UNIX time, or the amount of seconds since the epoch:

input = CURRENT_UNIX_TIME()

One thing you have probably noticed in Google Authenticator is that codes are valid for some time before changing to the next value. If the value would change every second it would be a bit difficult to copy, after all. This value defaults to 30 seconds, we can simply do an integer divide by 30 to get a value that will remain stable in a 30 second time window. We don't really care if the value has a particular scale, as long as the value is reproducible on both sides.

input = CURRENT_UNIX_TIME() / 30

Finally we apply the signing function, HMAC-SHA1:

original_secret = xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx secret = BASE32_DECODE(TO_UPPERCASE(REMOVE_SPACES(original_secret))) input = CURRENT_UNIX_TIME() / 30 hmac = SHA1(secret + SHA1(secret + input))

Now, we could be done here as what we have so far will provide effective 2FA. However the resulting HMAC value is a standard-length SHA1 value (20 bytes, 40 hex characters) and nobody wants to type 40 characters. We want to those pretty 6-digit numbers!

To convert the 20-byte SHA1 to a 6-digit number we'll first slim it down a bit. We will use the last 4 bits of the SHA1 (a value ranging from 0-15) to index into the 20-byte value and use the next 4 bytes at that index. The maximum potential value of this indexing operation is 15 + 4 = 19, which is also the maximum index possible (remember, zero-based) so that will always work. So anyway, we get those 4 bytes:

four_bytes = hmac[LAST_BYTE(hmac):LAST_BYTE(hmac) + 4]

We can now turn these into a standard 32 bit unsigned integer (4 bytes = 32 bit).

large_integer = INT(four_bytes)

Now we have a number, much better! However as the name suggests, this could still be a very large value (2^32 - 1), and that would obviously not be a 6 digit number. We can guarantee a 6-digit number by using the remainder of dividing by the first 7 digit number. Which is one million.

large_integer = INT(four_bytes) small_integer = large_integer % 1,000,000

This is our final value. Here's everything together:

original_secret = xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx secret = BASE32_DECODE(TO_UPPERCASE(REMOVE_SPACES(original_secret))) input = CURRENT_UNIX_TIME() / 30 hmac = SHA1(secret + SHA1(secret + input)) four_bytes = hmac[LAST_BYTE(hmac):LAST_BYTE(hmac) + 4] large_integer = INT(four_bytes) small_integer = large_integer % 1,000,000

For a more realistic example with code that actually runs I implemented the above algorithm in Gohttps://github.com/robbiev/two-factor-auth

avatar