第50話で、イトはexpired old sessionを延命しなかった。
fresh authenticationからnew identifierとnew server rowを作り、old replayは401のままにした。
encore controlは200になった。
ところが、account protection modeの扉だけは開かない。
first evidence lampはgreen。
second factor lampはdarkだ。
「入力が二回ならいいんだよね」
イトはさっき通ったpassword cardをcopy splitterへ差し、同じcardをsecond holderにも置こうとした。
protected settingを確定できるのは、あと四十五秒。
二つの入力欄ではなく、二種類のevidence
ピコはsplitterへ触れず、first / second holderの間へcategory separatorを立てた。
イト
同じpasswordを二回確かめれば、checkは二つになるよね?
ピコ
checkの回数は増える。でも、authentication factorの種類は増えていないよ
イト
factorって、入力欄の名前じゃないの?
ピコ
本人が何をcontrolしていると示すevidenceのcategoryなんだ
この話のaccount service、factor rails、TOTP authenticator、verifierは、外のInternetから切り離した学習fixtureだ。
実account、password、TOTP seed、recovery code、production timeoutは使わない。
SMS、email、push、passkey、security key、biometric、factor replacement / recoveryの優劣もこの一件では決めない。
factorは「何を持つ/知る」と証明するか
NIST SP 800-63 Digital Identity Modelは、authentication factorを大きく三つに分ける。
something you know。
something you have。
something you are。
passwordは、subscriberが知るsecretをverifierへ示すknowledge factorだ。
cryptographic key等を含むregistered authenticatorをcontrolしていることは、possession factorになり得る。
biometric characteristicはinherence factorの入口になるが、NISTの枠組みでは単独secretとして扱わず、physical authenticatorと組み合わせる条件がある。
ここで大事なのは、同じcategoryのevidenceを二つ並べても、異なる二factorにはならないことだ。
NISTのmodelも、user-generated PINとpasswordはどちらもsomething you knowなので、二つ提示してもsingle-factorだと明示する。
「passwordを二回」も、「passwordと別のmemorized PIN」も、このfixtureではknowledge rail一本の中にある。
codeという形だけではfactorを決められない
second holderは数字を要求している。
でも、数字だから自動的にsecond factorになるわけではない。
memorized PINならknowledgeかもしれない。
registered authenticatorが内部secretと時刻から作るone-time passcodeなら、そのauthenticatorをcontrolしていることを示すpossession evidenceとして使える。
NIST SP 800-63B-4のAuthenticator Requirementsは、OTPをauthenticatorが生成し、そのauthenticatorのpossessionを示すため一度だけ使うsecretとして整理する。
「六桁を知っているからknowledge factor」と、見た目だけで分類しない。
どのauthenticatorへ何がboundされ、verifierが何を照合しているかを見る。
TOTPは、時刻をmoving factorにする
今回のsecond railには、事前にfixture accountへ登録したsoftware TOTP authenticatorがある。
enrollment時にauthenticatorとverifierが対応するsecret materialを持つ。
login時、authenticatorはそのsecretとtime stepからshort-lived valueを作る。
RFC 6238は、HOTPのmoving factorをcounterからtime valueへ置き換えるTOTP algorithmを定義する。
この回はalgorithmを自作しない。
real seedを画面へ出さず、trusted library / authenticatorの検証境界として扱う。
time stepの長さ、許容clock skew、digits、attempt limitはsystemごとに設計する。
「TOTPはいつでも六桁・六十秒」と一律に決めない。
short-livedでも、何度も通してよいわけではない
fixture verifierには三つのcheckがある。
accountへboundされたauthenticator由来か。
current acceptance window内か。
そのOTP valueをすでにacceptedにしていないか。
OWASP Multifactor Authentication Cheat Sheetは、OTPにshort time-to-live、single use、attempt limitを持たせ、successful verification後にinvalidateする運用を勧める。
画面から数字が消えるまで、同じvalueを何度でも通す設計にしない。
codeをlogや長期plaintext storageへ残すことも避ける。
このfixtureは一回のaccepted / replayだけを再現し、rate limitやaccount recoveryは別の設計課題として境界外に置く。
イトの前に、三つの選択肢が開く
protected settingの締切まで、あと二十五秒。
A same password cardをsecond holderへcopyする
二つのholderは埋まる。
しかしknowledge evidenceを複製しただけで、passwordを知る一つのfailureから独立しない。
B 別のmemorized PIN cardを置く
valueは違う。
でもpasswordと同じsomething-you-know railで、異なるfactor categoryにならない。
C passwordとregistered TOTP authenticatorを別railで照合する
first railにはknowledge evidence。
second railには、registered authenticatorが今作ったpossession evidence。
verifierはcategory、binding、current window、used statusを分けて照合する。
ピコはpassword cardにもTOTP authenticatorにも触れなかった。
「二枚に増やすんじゃない。違うrailを、自分で通す」
イトはCを選んだ。
copy splitterをclosed boxへ戻し、left knowledge railへpassword evidenceを、right possession railへ自分で起動したregistered TOTP authenticatorのcurrent one-time cardを置いた。
one categoryは止まり、two categoriesは通る
イトは最初にcomparison traceを流した。
first holderとsecond holderへsame password evidenceを置く。
password verificationは二回ともmatchした。
でもcategory counterはknowledge oneのまま。
factor gateはone categoryとしてprotected settingをclosedにした。
次にイトは、password evidenceとcurrent TOTP valueをseparate railsへ置いた。
verifierはpassword matchをknowledge railで確認する。
TOTP valueはregistered authenticator binding、current window、unused statusをpossession railで確認する。
二本のrailが初めてgreenになり、protected settingへaccepted cardが返った。

「二回正しい」じゃなくて、「違う種類を二つ示した」が通過条件だった。
accepted OTPを、もう一度使わない
イトは同じTOTP valueをreplay trayへ移した。
time windowはまだ閉じていない。
valueの形も正しい。
しかしverifierのused markerはclosedだ。
replay requestにはrejected cardが返った。
new valueが必要な次のauthentication eventまで、accepted valueを再利用しない。
これでworkbenchには三つのobservable resultが並んだ。
password + same passwordはone-category rejection。
password + current registered TOTPはtwo-category acceptance。
accepted TOTPのreplayはrejection。
protected settingが確定し、second factor lampがgreenになった。
MFAは強くするが、入力先を本物にしない
passwordだけを盗まれた場面では、別factorを要求することで止められる範囲が増える。
ただし「二factorだから、どんな入口でも安全」ではない。
manual-entry TOTPは、userがvalueを偽のverifierへ渡せば、その短い時間内に中継される可能性がある。
NISTはpasswordをphishing-resistantとは扱わず、authenticator outputをverifier固有のchannelへcryptographically bindする性質をphishing resistanceの境界として分ける。
OWASPもsoftware TOTPをshort-livedだがphishing susceptibleな方式として整理する。
この回はphishing-resistant authenticatorのprotocol比較へ進まず、「MFA」と「phishing resistance」は同義でないことだけを残す。
second factorを疑うときは、回数ではなくrailを見る
workbenchには四つの証拠が残った。
closed copy splitter。
separate knowledge / possession rails。
accepted後にusedとなったTOTP card。
one-category reject / two-category accept / replay rejectのthree result cards。
2FA / MFAを入力欄やstepの数だけで決めず、異なるfactor categoryのevidenceかを確認する。同じpasswordや別PINを増やしてknowledge一種類のままにしない。OTPを使うならregistered authenticatorとのbinding、short lifetime、single use、attempt limitをserver側で扱う。manual-entry OTPまで自動的にphishing-resistantとは決めない。
「二つ目のlampは、同じwireを二股にしても点かなかった」
イトはcopy cardを捨てずにclosed evidence trayへ残し、二本のfactor railだけをcurrent gateへ置いた。
そのとき、lab wallの裏側で、同じ形のsecond factor gateがもう一つ光った。
本物のgateではない。
でも、passwordとcurrent OTPの両方を要求している。
次回:二factorを、偽入口へ渡したら?
lookalike gateからurgent mailが届いた。
「残り十秒。passwordと確認codeを入力してください」
イトはcurrent OTP cardをholderへ入れず、差出人とexact URLを照らした。
次回、ピコルート第52話。
イトは、urgent mailのbuttonを押さなかった|fake login gateはどこで見抜く?

