Got Some \W+ech?

Could be Japanese. Could be English. Android, セキュリティ, 機械学習などをメインに、たまにポエムったり雑感記載したりします。

2017年を雑に振り返って、2018年の目標を雑に立てる

2017年振返り

1月

Android(Java)以外のプログラミングとして、初めてGoを弄り始める。自分ツールとして、GSuiteのコマンドラインツールをGoで作成。Slack Botも作成していたりしました。Reduxを勉強し始めている形跡があるが、正直ここらへんは自分のキャリアや人生に迷ってた間があります。後、副収入を得たのもここらへん。ちなみに、GSuiteツールキットは次のリポジトリ。正直ウンコだと思う。

github.com

2月

ちょびちょび前述のGSuiteのコマンドラインツールを作ってもいたけど、基本的にはDroidKaigiの準備をしていた模様。その過程で、使ってないActivityがあったら検知してくれるLintを作ったりしました。更新できてない... github.com

3月

DroidKaigiで「ドキッ★脆弱性 onCreate() から onDestroy() まで」発表。会社のアプリに脆弱性の報告をされたので、原因や対応フローといったのをコミュニティ内でシェア。Webアプリ(Railsエンジニア)の人と一緒にDockerデビュー。実はこのタイミングで、CISOの椅子を用意してくれていたスタートアップに転職しようとしていた。何やかんやあって、半年待ってもらうことに(結局、今の会社に残ったけど)

ドキッ★脆弱性 onCreate() から onDestroy() まで // Speaker Deck

4月

基本的に会社のことしかしてなかった。死ぬほど忙しかった。会社でWindowsサーバー・ドメコン・グループポリシーの権限部分でウンウン唸ってた。Twitterのタイムラインみると3am~4amまで仕事してた模様。引くわ〜。社長への報告とかもここから始まったかも。会社の全体的なセキュリティ方針とかお願いする予算とかも弾いてて、結構プレッシャー大きかった。ポッドキャスト「セキュリティのアレ」に準レギュみたいなポジションから参加したのも、ここらへんから。

5月

仕事については、大体4月と同じ。休日はTerraformをちょろっといじったりしてた。また、自分でコマンドラインを作ったりした結果、「もっとちゃんとプログラムの基礎やんないとなー」と思い立ってたのはここらへん。Googleが学生向けの技術開発者キャリアでやっておくべきことをリストしておいたので、そのチェックリストを作る。

github.com

6月

上記のを見て、暗号に関する授業をCourseraで修了。Andrew NG教授のMachine Learningもなんだかんだで終わってなかったの修了。両方ともCertificateは貰った。ただ、暗号の授業は面白かったけど、何となく思ってたのと違った。僕がのぞんでたのは、結城先生の「暗号技術入門」& 実装だったんだけど、Courseraは暗号が安全であるための数学的要件や攻撃方法がメインだった。なので「Javaで作って学ぶ暗号技術 - RSA,AES,SHAの基礎からSSLまで」を参考にして、Goを使った実装をしている。RSAとAESまでできたけど、SHAからSSLまでは出来てない。やるかは...わからない。色々やりたいことがあるので。あと、地味にGCP, コンテナ, k8sを使ったサイトを1つリリースしてた。更新は手動。

github.com

http://amzn.asia/crpzzCh

7月

仕事は相変わらず死んでたけど、技術的なことというより、非技術的な調整をしまくってて忙しかった。エンジニア is 何、セキュリティ is 何と超自問自答してた時期。 前述の暗号 in Goを実装しているときに、Techboosterのmhidakaさんにテクブで声をかけられる(もともとDroidKaigiで知り合いであった)。2つ返事でおkしたのが運の尽き。 ひーこらいいながら、AndroidのSMS Verifier APIについての初原稿を仕上げる。次のリンクから買えるで。

techbooster.org

あわせて、ssmjpで話してほしいといわれたので、やはり何も考えずに受けて、ひーこらいってた。NISTからDigital Identity Guide (SP800-63)がでたので、そのSMS認証について話す。これを日本語で不特定多数の前で話したのは、僕が初めて...かも...?

俺のSMS認証がこんなに非推奨なわけがない // Speaker Deck

GoogleのSecurity Princessと呼ばれる方が書いたセキュリティを専門にするひとの心得、というのを日本語訳した。これが結構バズった。そしてビビった。

ken5scal.hatenablog.com

8月

仕事は相変わらず(略。で、プログラミングしなさすぎてヤバイな、と思ったので、隙間時間で会社で使ってるサービスのAPIを叩くクライアントアプリを作成。コマンドラインも作っておいた。ビルドは手動でmakeファイルさえ作ってない。地味にAWSを始める(インスタンス立てるだけじゃなく、組織の中でちゃんと使う)。SlackのChat Botもここら辺でデビュー

github.com

9月

ソフトウェア的な活動は特にせず。お仕事は一旦落ち着く。ちょっとダレる。夏休みとしてエストニアに旅行にいく。 e-govショールーム、Funderbeam、Transferwise、Verif、Cybernetica、SK IDソリューション、エストニア情報センター(RIA)に訪問したりしていた。終わった後に、自分が所謂「日本企業の視察・情報収集」しかしてないことに気づき、激しく自己嫌悪。いや、日本のFintech事情とか話したけど、貰った情報の価値からしたらちょっと...。尚、ご飯は口に合わなかった模様。歴史的にはものすごい面白く、なぜエストニアが現在のエストニアになったかが理解できた。そして、その歴史的背景無視して日本が真似してもしゃーないのでは、というスタンスになった。そんな間に会社が上場。

10月

GCP, k8sでのインフラ構築2サイト目を構築開始。技術書典3に「ニッチ・セキュリティ」サークルから「現時点で日本語でググっても出てきにくいセキュリティ技術」を出す。自分はUAF 1.1に書いたが、一緒に参加頂いたbbr_bbqさんと北原さんの記事のクオリティの高さに完全降伏した。幸い好評のうち終了。

techbookfest.org

11月

GCP, k8sでのインフラ構築2サイト目の構築終了。色々あって神経をすり減らす。

12月

上記のサイトでバックエンドサーバーが必要になったので、gRPCデビュー。サーバー側はGoで、クライアント側はRubyで書いた。再度、mhidakaさんに誘われて、テクブ本を書く。今回のテーマはFirebaseを使った認証。何だかんだ言ってKotlinまだ触ってなかったので、全てKotlinで書く。

techbooster.org

ふりかえると

色々やってるな〜(小並 (´ε`;)ウーン…振り返ると殆ど仕事しかしてない気配です。何度か精神やばいな、っておもったことあるんで、ちゃんと休みはとろう。 今年の目標はQoLを上げるのも含めておいたいと思います。

で、これが去年の目標なわけだが、CISSP/機械学習/サービス作成というのができてませんな。 http://ken5scal.hatenablog.com/?page=1483260359

筋トレにあまりいけなくなっている事実は見過ごし難い。

そしてCNCFとの出会いや4月からの仕事で、完全に趣向が変わってきてはいる。

ブロックチェーンの流行りなど、新しい技術を眺めているだけでいいのだろうか。

CISSPとらなかったなあ

2018年の目標

やりたいことは沢山あるが、やはり基礎と認証・認可を固めて行こうと思う。また、攻撃技術は身に着けないとだめそう。コマンドライン自分で作ったけど、テストないと厳しい。QOLをあげるために、規則正しい生活を。

絶対やる

時間があったら

  • サービス作り。「Go Web Programming」
  • CISSP, CISA?
  • 「Real HTTP World」
  • 機械学習 -> 原点に立ち返って考えると、わいは異常検知をやりたかっただけなんや...個人的に数冊本読んで、kaggleに手をだす?
  • ブロックチェーン -> とりあえずフォロワーレベルでいいかな。本職はセキュリティで、いまだユースケースの確定してないところに本腰いれてつっこんでも迷子になるだけそう。入門書を数冊読んで、下を真似するぐらいで、今はいいかも。 Building Blockchain in Go. Part 1: Basic Prototype · Going the distance

Androidアドベンドカレンダー、Firebase Authenticationで電話認証する #Android #Authentication

Android アドベントカレンダー 20日目の記事です。

qiita.com

とある同人誌に掲載する予定だったのですが、風邪でぶっ倒れて書けなかった最終章をこちらに書きます。 内容は、Firebase Authenticationを使った電話認証のあれこれです。以降、「Firebase Authenticationの電話認証」を電話認証として略させて頂きます。 また、本稿ではFirebaseの仕組み上、みんなだいすき2要素認証ではなく2段階認証と呼称させていただきます。 詳しくはこちらをご覧ください。

blogs.manageengine.jp

本稿は次の内容でお送りします。 - ベーシックな電話認証 - 既存アカウントとのヒモ付け - 電話認証を使ったなんちゃって2段階認証 - SMS Retriever APIを使った半自動2段階認証

では、やってまいりましょう。

ベーシックな電話認証

いきなりで申し訳ないのですが、電話認証を実装したアプリはエミュレータ上では実行できません。いや、実行はできますが、電話認証周りの機能は動きません。クラッシュとかではなく単純に動きません。実機をご用意ください。

まずは電話番号をFirebaseに登録する必要があります。その場合、1) その電話番号が本当に実在するものか、2) 登録要求をリクエストしたユーザーのものであるか確認をとる必要があります。コードでお話すると、まず PhoneAuthProvider.getInstance().verifyPhoneNumber で電話番号の存在を確認し、そして、その後SMS経由で送られた確認コードをユーザーから受理・検証することで、登録要求リクエストの真正性を確認します。

1) はFirebaseの PhoneAuthProcider.getInstance().verifyPhoneNumber を使って出来ます。

   // 該当の電話番号に確認コードを送った結果を受け取るコールバック
        mCallbacks = object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
            // 後でつかいます
            override fun onVerificationCompleted(p0: PhoneAuthCredential?) {
                Toast.makeText(this@EmailPasswordActivity, ": Verification Completed", Toast.LENGTH_SHORT).show()
            }

            // 後でつかいます
            override fun onVerificationFailed(p0: FirebaseException?) {
                Toast.makeText(this@EmailPasswordActivity, p0?.message, Toast.LENGTH_SHORT).show()
            }

            override fun onCodeSent(p0: String?, p1: PhoneAuthProvider.ForceResendingToken?) {
                mSMSVerificationID = p0.toString()
            }

            override fun onCodeAutoRetrievalTimeOut(p0: String?) {
                mSMSVerificationID = p0.toString()
            }
        }


    private fun registerPhoneNumber(phoneNumber: String) {
        PhoneAuthProvider.getInstance().verifyPhoneNumber(
                phoneNumber, // E.164フォーマットである必要があります。このフォーマットは[+][国コード][エリアコード]になります。例えば080-1234-5678が電話番号なら、E.164フォーマットで+818012345678です。
                10, // 10秒でタイムアウトする
                TimeUnit.SECONDS,
                this@EmailPasswordActivity,
                mCallbacks
        )
    }

2) は真正性確認になります。ユーザーが取得した確認コードとmCallback内で取得したSMS確認IDを組合せてたクレデンシャルがまずは作成されます。アプリはそれをサーバーに送信し、サーバーはそれを検証します。

val auth = FirebaseAuth.getInstance()
val credential = PhoneAuthProvider.getCredential(mSMSVerificationID, verificationCode)
auth.signInWithCredential(credential).addOnCompleteListener { task ->
    if (task.isSuccessful) {
        auth.currentUser?.let { updateResult(it) }
    } else {
        Log.w("Phone", "signInWithPhoneAuthCredential:failure", task.exception)
        Toast.makeText(this, "Authentication failed.", Toast.LENGTH_SHORT).show()
    }
}

タスクが成功した場合、その時点で電話認証をしたユーザーはFirebaseに登録されていることになります。次の画像をご参照ください。

f:id:kengoscal:20171217011643p:plain

とてもハンディですね。

既存アカウントとのヒモ付け

でも、これでは既存アカウントに紐付いてません。単純に、新しい別のアカウントが生成されただけです。既存アカウントに紐付かせるために、電話認証で登録したアカウントを削除したうえで紐付かせたいアカウントにリンクさせてみましょう。下記の様にログイン済みのユーザーにクレデンシャル(SMS確認IDとSMSに送られた確認コード)をリンクさせればおkです実装すればおkです。

val auth = FirebaseAuth.getInstance()
val smsCredential = PhoneAuthProvider.getCredential(mSMSVerificationID, findViewById<TextView>(R.id.mfa_code).text.toString())
auth.currentUser?.linkWithCredential(smsCredential)?.addOnCompleteListener { task -> // auth.currentUserはFirebase Authenticationですでにサインインしているホスト
     if (task.isSuccessful) {
          mAuth.currentUser?.let { updateResult(it) }
     } else {
          Toast.makeText(this, task.exception?.message, Toast.LENGTH_LONG).show()
     }
}

ひも付きました。

f:id:kengoscal:20171217015652p:plain

次は2段階認証の話になります。

電話認証を使ったなんちゃって2段階認証

上記の通り、複数の認証プロバイダ(メールアドレス、電話番号)を1つのアカウントに紐付けることができました。そこでメアドとSMSを使った2段階認証を設定してみたいと思います。 注意: 今のFirebaseの仕組み上、メアド・パスワードの認証が成功した時点でサインインした状態になってしまいます。従って、一度サインアウトして更に電話認証する流れになります。なので、本章はなんちゃってとなっています。

流れとしては、signInWithEmailAndPasswordでサインインしたユーザーの情報から電話番号を取得し、確認コードを送ります。これはFirebaseのContinuationインターフェースを使って実現できます。ContinuationインターフェースではTaskの結果を受取り、任意の処理を実行・出力する実装ができます。

// 認証結果を元に、電話番号へ確認コードを送る
class Send2FAVerificationCodeToSMS(
        private val executor: Executor,
        private val callback: PhoneAuthProvider.OnVerificationStateChangedCallbacks) : Continuation<AuthResult, Unit> {
     override fun then(task: Task<AuthResult>) {
         if (!task.isSuccessful || task.result.user.phoneNumber.isNullOrEmpty()) {
             return
         }
         return PhoneAuthProvider.getInstance().verifyPhoneNumber(
                task.result.user.phoneNumber.toString(), // Needs to be E.164 format. eg. +81805541xxxx(Japan), [+][country code][subscribed number with area code]
                10,
                TimeUnit.SECONDS,
                executor,
                callback
        )
    }
}

// 何となく別スレッドで処理したかった
class ThreadPerTaskExecutor : Executor {
    override fun execute(r: Runnable) {
        Thread(r).start()
    }
}

// 上記をsignInWithEmailAndPasswordのタスク終了後に実行する
mAuth.signInWithEmailAndPassword(email, password)                    
                .continueWith(Send2FAVerificationCodeToSMS(ThreadPerTaskExecutor(), mCallbacks))
                .addOnCompleteListener { task ->
                    signOut() //signInWithEmailAndPasswordが成功した時点で、サインイン済みになってしまっているのでサインアウトを実施
                    if (!task.isSuccessful) {
                        Toast.makeText(this, task.exception?.message, Toast.LENGTH_LONG).show()
                        return@addOnCompleteListener
                    } else {
                        Toast.makeText(this, "Verification Code has been sent", Toast.LENGTH_LONG).show() 
                    }
                }

手元の携帯電話に確認コードが送られてきました。前章で紹介したとおり、このコードと確認IDを組合せたクレデンシャルを引数にするsignInWithCredential を呼び出せば、メールアドレス認証と電話認証を組合せた2段階認証の出来上がりです。

SMS Retriever APIを使った半自動2SV認証

ところで皆さん、2SVするとき電話番号入力するのめんどくさくありませんか?次のような手順を見て頂ければ、半分くらいのかたには同意頂けるかと思います。

  1. 自分の電話番号を入力
  2. サーバからの認証コードを待つ
  3. SMSまたは電話アプリを立ち上げる
  4. 認証コードを入力

このステップ2からステップ4までを自動化してくれる仕組み、それがGoogleがだしているSMS Retriever APIです。 当該APIを使うことで、サーバからSMSを受け取ったAndroid端末(のGoogle Play Service)がブロードキャストし、特定のアプリがそれを受信・SMSをパースできるようになります。 パースさえできれば、その後処理でサーバに認証コードを送るだけなので、ユーザー体験を損なわない自動的な2段階認証を提供できるわけです。

以下、実装を軽くみていきます。 注意: なお、筆者はスマホ(SIM Free機)と電話を分けて運用しているので、本章は動作確認できていません。

SMS Retriever APIの呼び出し

SmsRetrieverClient インスタンスを生成し、startSmsRetriever()を呼びます 立ち上がったAPIもといタスクは認証コードを含んだSMSが届くのを待ちます。5分立つとタイムアウトしますが、待ち時間は変更できます。

class PhoneNumberVerifier : Service() {

    private var smsRetrieverClient: SmsRetrieverClient? = null

    override fun onCreate() {
        smsRetrieverClient = SmsRetriever.getClient(this)
    }

    // このサービスは `PhoneAuthProvider.getInstance().verifyPhoneNumber` の実行直後に呼び出される
    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        super.onStartCommand(intent, flags, startId)

        val action = intent.action
        if (ACTION_VERIFY == action) {
            val task = smsRetrieverClient!!.startSmsRetriever()
            task.addOnCompleteListener {task ->
                if (task.isSuccessful) {
                     // 何か. smsRetriever開始成功のお知らせ
                } else {
                     // 何か. smsRetriever開始失敗
                }
            }
}

SMSから認証コードの取り出し

認証コードが端末に届いた際、Google Playサービスが、SmsRetriever.SMS_RETRIEVED_ACTIONを指定した明示的なブロードキャストを発信します。このブロードキャスト内に認証メッセージが届くわけです。従って、アプリ内ではBroadcastReceiverで本メッセージを抽出します。

class SmsBrReceiver : BroadcastReceiver() {

        override fun onReceive(context: Context, intent: Intent?) {
            if (intent == null) {
                return
            }

            if (SmsRetriever.SMS_RETRIEVED_ACTION == intent.action) {
                val extras = intent.extras
                val status = extras!!.get(SmsRetriever.EXTRA_STATUS) as Status
                when (status.statusCode) {
                    CommonStatusCodes.SUCCESS -> {
                        val smsMessage = extras.get(SmsRetriever.EXTRA_SMS_MESSAGE) as String
                        Log.d(TAG, "Retrieved sms code: " + smsMessage)
                    }
                    CommonStatusCodes.TIMEOUT -> doTimeout()
                    else -> {
                    }
                }
            }
        }
}

ここで取得したsmsMessage = 確認コードを、前述のsignInWithCredentialにいれてFirebaseに送信することで、半自動2SVが完了します。

//mSMSVerificationIDはPhoneAuthProvider.OnVerificationStateChangedCallbacks()のonCodeSentから取得
val credential = PhoneAuthProvider.getCredential(mSMSVerificationID, code) 
mAuth.signInWithCredential(credential)

以上です。

終わりに

以上で、Firebase Authenticationの電話認証周りの紹介をさせていただきました。認証システムは設定するには非常に多くの考慮が必要ですので、Firebase Authenticationを利用すれば、ベストではないにせよ2段階認証までハンディに実装できるようになります。

High Sierraのパスワードレスrootログインの注意点と対策方法

japanese.engadget.com

話題になってるので、改めて説明をする必要はないと思うので、注意点・対策方法について記載しておく。

注意点

どこかの記事の対策として"root"を無効化する、とあった。でも、rootと打ち込むと勝手に有効化されるので意味がありません。パスワードを変更してから、無効化してください。

パスワード変更

ローカル管理者権限を持ってる場合

下記のうちいずれか

  • CLIベース % sudo passwd root

  • GUIベース

  • システム環境設定 > ユーザーとグループ > ログインオプション > 編集 f:id:kengoscal:20171129122002p:plain

  • ディレクトリユーティリティを開く > 編集 > ルートパスワードを変更 f:id:kengoscal:20171129122212p:plain

↑のいずれの方法でも対策できるのは確認済み

組織内の端末管理者向け

組織の管理者だったら、Mac管理ツールで下記のスクリプトを配布すればいいと思います。こちらも大丈夫そう。検証してから使ってね。

Blocking logins to the root account on macOS High Sierra | Der Flounder

余談

報告者のtweetを見にいったところ、公開方式について ちゃんとDisclosure Policyに従って報告しろよ派 vs Appleが悪いのに何がダメなんだ。それを気にするのは報告者の責任ではない派 の論争が繰り広げられてて面白かった (コナミ

f:id:kengoscal:20171129122910p:plain

GCPのIdentity-Aware Proxyためしてみた #GCP #IAP

f:id:kengoscal:20171112001203p:plain

GCPで動かしてるWebサービスstg環境にIdentity-Aware Proxy(IAP)噛ませてみた。これにより外部からアクセスする際、ドメインのサイトにたどり着く前にGoogleアカウントの認証が必要になった。事前に許可されたGoogleアカウントでなければサイトにたどり着くことすらできなくなる。つまり、アカウントとクレデンシャルが正しかろうと、IAPに登録されてなければ、アクセス権限が一切ない状態になる。

設定方法は簡単で、「IAM & Admin」 > 「Identity-Aware Proxy」で対象のリソースでIAPを有効化させるだけ!簡単。f:id:kengoscal:20171112000326p:plain

なお、Firewallでガバガバに設定していたりするとIAPをバイパス出来てしまう。その場合、warningサインがでていることになるらしい。僕の場合は、大体プロジェクト作成時にdefault firewall ruleを消してしまうので、そういうことはなかった。

* 元サイト f:id:kengoscal:20171111235612p:plain

  • IAPをかませると誘導される画面 f:id:kengoscal:20171111235931p:plain

  • 失敗画面(実在するアカウントでためした) f:id:kengoscal:20171111235849p:plain

こいつのイカス所は、アクセス権限対象を細かく切れるところだと思う。 Googleアカウントはもちろんのこと、サービスアカウント、Googleグループメール、ドメイン全体など様々なスコープに対応している。例えば、外部協力会社さんが既に保持してるGoogleアカウントをそのまま使えることができる(GSuiteに新規登録して月額支払わなくていい) f:id:kengoscal:20171112003536p:plain

以上。

DockerfileのADD/COPYに--chownオプションができた

  • 11/10: 追記。CI/CDでの制限について書いてなかった。

Dockerのベストプラクティスに、サービスをnon-rootユーザーで走らせなさい、というのがある。

docs.docker.com

そうすること自体は簡単なのだけれども、当然ながらユーザー権限にあわせてコンテナ内のファイル等の権限を設定しなきゃいけない。仮にUSER指定した後にCOPYしてもroot:rootの権限になるので、別途chownをしてやらなければならなかった。

USER app
COPY . $APP_DIR  # $APP_DIRの権限はroot:root
RUN chown -R app:app $APP_DIR

RAILSなど関連ファイル数が結構な量になるサービスの場合、すべての権限が変わるまで10min~15minとか余裕でかかってた。このせいで、dockerのベスプラに従ってなかった人は多いと思う。僕も無視してた(ごめん)

それがv17.09.0-ceから解決された。

Release v17.09.0-ce · docker/docker-ce · GitHub

まあ、端的にいうと ADD/COPYchown をオプションでつけられるようになったのだ。

USER app
COPY --chown=app:app . $APP_DIR

当然ビルド時間も気にならないぐらい短いので、是非dockerのベスプラに従っていこう。

追記

尚、CI/CDのDockerのバージョンがv17.09.0-ceでなければ意味がない。例えばGCPのContainer Builderはv17.06ぐらいなのでビルドに失敗する。考えてみれば当たり前である...

SMSによる2要素認証は本当に非推奨なのか?

きっかけ

ssmjpで発表してきました。最近、「NISTはSMSによる2段階認証を非推奨」という記事をよく見るようになりました。でも、それって昨年度のPreview版の話で、2017年7月のPublic版でもそうなの?という疑問がわいたので、根性だしてNIST SP800-63bを読んできました。

結論

Public版では非推奨ではありません。CISTによる指摘を、NISTが受け入れたようです。ただ、非推奨をそのまま取り下げたのではなく、SMSを超えて公衆交換電話網(PSTN)経路のOut-of-Band認証にスコープを広げ、「コレを使うならあれせいこれせい」といった諸条件を追加しています。このために、RESTRICTEDな認証と分類されています。ちなみに他の認証方式にRESTRICTEDに分類されたものはありません。

課せられた条件とは。

ちなみに諸条件は、下記の通りです。 * RESTRICTED以外の認証方式を1つ以上提供しなければならない * RESTRICTED認証方式のリスクアセスメントをしなければならない * リスクアセスメントの結果を利用者にわかりやすい形で届けなければならない * RESTRICTED認証方式が禁止されたときに備えた移行プランを準備しなければならない

B2BならいざしらずB2Cなサービスに2段階認証を整備するとなると、PSTN経路のOut-of-Band認証方式はほぼ避けられないですね。厳しいです。ちなみに日本においてPSTN経路は廃止される予定ですが、総務省の計画では2025年です。それまで2FAを準備しないのは、まあ、ないでしょうね… 米国でのサービス展開を考えているなら、今から対応しておいたほうがよさそうです。

ただ、アメリカみたいにグローバルなIT企業がばっこしているところだろ、本国のPSTNは安全でも、途上国のは脆弱な経路になるんだろうなぁ…とも思っています。

余談

NISTのパブコメGithubで公開されています。本件のissueは下記をご参照ください。

github.com

色々差を感じるなぁ…エクセルやめようぜ…

(翻訳)セキュリティで飯食いたい人向けの行動指針

  • (7/21) コメント欄の指摘を受け英訳追記

前文

本記事はGoogleのセキュリティ担当者 Parisa Tabriz氏(異名: Security Princess)のSo, you want to work in security?を翻訳したものです。

うっ…半年以上前…

意訳したりわからない部分もあったので、原稿の全てを反映できているか自信はありません。元ブログも是非ご一読ください。

—————————————- ここから翻訳 ————————————————-

セキュリティ分野(コンピュータ、情報、サイバー…etc)でキャリアを積みたい人からメールをもらうことがある。素晴らしいことだと思う。テクノロジーを安全にしていくパション、創造性を持ち、ハードワークをこなせる仲間はいつだって必要だ。金銭的な意味で、安定した生活を送れるようにもなるだろう。

他にも同じトピック(キャリア)で似たようなポストがあるが、私の経験から導き出した上流の考えを共有していこうと思う。

警告: 映画のような華々しさはない

実際の現場はハリウッド映画とは違う。私はハッカー映画やドラマは好きだが、私の仕事の経験上、映画のようなスリルでセクシーな場面には遭遇しない。 しかし、(恐らく他の職種もそうだろうが)セキュリティはとても刺激的で、チャレンジングな、そしてやりがいのある仕事だと思う。

完全もしくは標準的なカリキュラムなどない

セキュリティは広範で、インターディシプナリー(学問的横断)で、応用的な分野だ。セキュアなシステムをデザイン・構築する、それを攻撃する、検知する、など役割は多岐にわたる。そのなかに唯一無二で標準的なカリキュラムなどない。この分野がより成熟するにつれ、カリキュラムも充足してくるかもしれないが、私はそうなるとは思えない。

もし、あなたがコンピューターサイエンス、コンピュータ、ソフトウェアの仕組みを理解するのであれば、それらは大いに役に立つであろう。コンピューターサイエンスは抽象的なレイヤーの問題を解決する学問であり、セキュリティはその抽象レイヤーにおけるミスを見つけ直す(もしくは攻撃する)学問だ。

私はイリノイ大学のコンピューターサイエンス部で学んだ。中でもOS、ネットワーク、コンピューター・アーキテクチャコンパイラーなどのコースが役に立った。それに加え、私が興味をもった技術コース(信号処理、バイオメディカル工学、人工知能)や、インターン、学生クラブのプロジェクトで携わったネットワーク、プライバシー向上技術、Web/クライアントアプリ作成などで経験と積んだ。

ユーザーや顧客がどのようにテクノロジーを使うか理解するのも有効だ。もし私が大学に戻るのであれば、心理学、社会学ヒューマン・ファクターのコースをとるかもしれない。

私は似たようなバックグラウンドを持つ専門家とも、そうでない専門家とも仕事をしたことがある。専門家には学位を取る前に中退した人もいる。

私は特にセキュリティの資格をもっていない。それによって不利益を被ったこともない。なにかしらの産業や国ではプロフェッショナルとして必要かもしれない。they’re certainly a thing that some reasonable people have pursued — caveat emptor(?) -> 持っていた方が雇い主が安心できるケースはあるかもしれない。

ハッカーの文化を理解するために、Hacker ManifestoやHow to Become a hackerを読むといいだろう。セキュリティ専門家の行動指針・行動規範になるだろう。もし、ハッカーでなくても、ハッカーマインドセットを理解するのに役立つはずだ。

他にも色々なインプットをする場がある。私がインプットする先はこのTwitter security listにいるひとたちからであることも多い

手を動かせ。実践しろ。

どの業種でもいえることだが、業務経験はなるべくはやく始めることだ。始めることで興味、強み、将来のキャリアプランを計画できる。日常業務や環境がどういった要素から構成されており、そのうち何が好きで何が嫌いか学べる。私の人生で最も価値があった経験の一つは、おおよそ全く好きになれなかったインターンシップだ。私の将来の方向性は大きく変化した。

どのように業務経験を始めるかは人による。学生クラブやキャリアフェアに出席し、熱意を向けられるインターンシップやバイトに応募しよう。私の場合、ライフガードコミュニティでやっていた清掃バイトの伝手で、大学寮のシステム管理業務をやることになった。ここで積んだ経験を活かし、大手製薬会社でITインターンをすることになった。また、授業ではなく大学のクラブ内で実際のソフトウェア作成の経験をつみ、サイバーセキュリティインターンシップをみつけた。こうやって私は、Googleの中のひとに「どれいっちょ面接するか」と思ってもらえるぐらいの経験を積んだ。

コードを書け

私の知っている優秀なセキュリティエンジニアは、コードをよく書く。ソフトウェアを書くことで、セキュリティ的なバグを埋め込むこともある。この過程から開発者に対してリアルな共感をもつことができるのだ。結局のところセキュアでないコードを指摘するより、継続してセキュアなコードを作っていく方が難しいことを認知できる。

もし、どこから始めれば良いのか分からければ、オープンソースのバグを潰すところから始めるといいだろう。バグ潰しは感謝される。プロジェクトのメンバーに感謝されるだけでなく、将来的な仕事につながることもある。

コードを壊せ

ソフトのバグを探すことに時間を費やせ。デバッガ・ネットワークスキャナー・ウェブプロキシ・ソフトウェアfuzzerの使い方を学ぼう。ハッカープレイグラウンドで遊ぼう。私は大学の時、http://seclists.org/bugtraq Hack This Site!をつかっていた。他のハッカー養成場は https://infosec.rocks.にリストされている。CTFなどのハッキングチャレンジりすとはここだ。バグバウンティをやっている会社にばぐを報告するのもよいだろう。

バグを探すだけでなく、bugtrag/fulldisclosure/oss-secから他者がみつけたことを追い、学ぶことも推奨する。

知識を共有しろ

私は大学時代に、ACMグループのSigMil(?)にいた友人からセキュリティを教わった。そこでは興味のある分野についてプレゼンをするメンバーがいた。我々はまた、DEFCONへ巡礼したり、セキュリティ本を買ったり、外国の同じ志をもつ同士と成果物についてチャットしあったりした。Googleでは、専門性・苦心していること・半熟なアイディアを同僚と共有することで、たくさんのことを学べた。

知識の共有はいくつかの理由で重要だ。 1. 知識の共有は、セキュリティのベストプラクティスやハマリポイントを横断的に展開していくのに有効だ。 2. プレゼンやドキュメントの作成の過程でたくさんのことを学べるので、隠れたトピックまで見渡せられる 3. 質問・コメント・ディスカッションを通して、聴講者からも学びがある。 4. Pay it forward(?) -> その恩は周囲の人にも広がる

本当にたくさんのことを学んだ。

コミュニケーションを怠るな

セキュリティをするということは、同じバックグラウンドを共有しない人に対して、複雑な技術的問題を日常的に説明することになる。そして、聴講者はそれぞれ異なる単語・専門性・動機をもつことになるだろう。あなたは脆弱性の重要さについて国際的な基準にたよることは滅多にできないし、セキュリティのプラクティスを実践するときに、輝かしいデモはできない。あなたは、聴講者にフラストレーションを感じさせてはならない。

これをするにはコミュニケーションが必要であり、時には説明と交渉をしなければならない。技術的リソースだけでは身につかないため、練習し、パブリッシュし、継続的に向上させていかなければならない。

辛いことも失敗もある

当たり前のことだが、明確にしておきたい。 セキュリティは大変な仕事だ。我々が古いものを撤廃するより圧倒的早く、我々が守るべき技術分野は変わる。従って、新しいことを学び続けねばならない。攻撃者は我々より時間とリソースを持っており、既存の防御手法にも追いつきやすい。

セキュリティはストレスの多い仕事だ。不明瞭な問題や不完全なソリューション、あまりないデータ、何より人の安全を脅かす現実の脅威と向き合わなければならない。

セキュリティは成功を可視化しにくい仕事だ。私の経験上、失敗の方が人の目につきやすい。だが、我々は究極的にリスク緩和までしか対応できず、銀の弾丸は存在しない。

楽観者でいよう

先述の通り、 (‘A`)ウツになることもあるであろう。テクノロジーの進歩についていけないと思うかもしれない。2016年の今日でもバッファオーバーフロー脆弱性を利用して、インパクトのでかい攻撃をされている。セキュリティは不可能であり、悪くなっており、なぜ我々が失敗してるか指摘する人を良く見ることになるだろう。

現実は辛いかもしれない。だが、テクノロジーが我々にもたらしたことを考えてみよう。その成果はすばらしいの一言だ。もちろん完璧ではないし、将来的にも完璧にはならない。だが、セキュリティは10年前より確実によくなってるし、それなりのレベルで保証されるようになってきている。だから私は楽観者でいられる。

助けを求めよう

嫌な奴はいる。嫌な奴にくじかれるな。男性優位主義でエゴイスティックな側面を長いことみてきた。会話がマウント取りに発展することは珍しくない。

私の今までの成功は、他のセキュリティ専門家の人の支援・アドバイス・教育からなっている。助けを求めても、それは仕事から外されるということではない。

なので、助けが必要であれば聞こう。デューディリジェンスをちゃんとし、助けを提供しやすいようにしよう。スコープを適切に切って、コンテキストを共有し、タイポを減らせば、良いレスポンスが返ってくるはずだ。

Good luck and happy hacking!