【Bat+PowerShell】バッチファイルでパスワードなどの入力をマスクする(隠す)方法!

Windows


こんにちは!今回はバッチファイルでインプットを「*」にマスクする方法を紹介していきたいと思います。

「ショルダーハッキング」という言葉を聞き覚えないでしょうか?企業などにお勤めの方ですと、もしかしたらセキュリティ講習などで耳にしたことがあることがあるかもしれません。

要は、肩越しに入力している情報をのぞき見されてしまうことですね。

人の目は背後までは注意しきれないものです・・・。

パソコンに限らず、通帳や手紙、社外秘資料など・・・のぞき見されてしまう事は意外にたくさんありますね!

今回はパスワードなどを入力するとき、画面に入力そのままが表示されないようにするバッチファイルの作成方法を紹介していきます。

やりたいこと

まず、普通にバッチだけでユーザーに入力させるには「set /p」をよく使います。
例としては↓のようなコードになると思います。

@echo off
set /p PASSWORD="パスワード="

ためしにこれを実行して「password」と入力してみます。

するとこのように入力した中身が全部見えてしまいます。
これではのぞき見されても文句言えませんね。

これを改善するために、紹介する方法で隠して(マスク)みます。

するとこのような感じで、入力した文字から「*」に置き換えられるようになります。
これなら画面を見られても何が入力されたかはわかりませんね!

スクリプト例

@echo off

set "pscmd=powershell.exe -Command " ^
$inputPass = read-host 'パスワード=' -AsSecureString ; ^
$BSTR=[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($inputPass); ^
[System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)""

for /f "tokens=*" %%a in ('%pscmd%') do set PASSWORD=%%a

echo %PASSWORD%
pause

このコードをテキストファイルなどに張り付け、拡張子を「.bat」にすればテストすることができます。

解説

バッチファイル内でPowerShellコマンドを実行する

今回は、バッチファイルで実現したいのですが、用意されている入力用のコマンドにはマスクするオプションが見つかりませんでした。そのため、パワーシェルで入力作業を肩代わりさせています。

set "pscmd=powershell.exe -Command "[PowerShellコマンド]""

バッチ内でPowerShellコマンドを実行する場合は、「powershell.exe -Command」をつけてPowerShellコマンドを[PowerShellコマンド]の部分に書き込んであげればOKです。

コマンドは後で結果を取得するときに扱いやすいように「pscmd」という変数に格納しています。

バッチファイル内では空白があると別のコマンドとして誤認識する恐れがあるので、「"」でくくるのは鉄則です。setごと全部と、PowerShellコマンド部分には必要でしょう。

スクリプトコード内にある「^」はコードが改行されていることを意味します。
バッチファイル内では「^」を使うと1行だと読みずらいコマンドを改行して実行ができます。

入力をマスクする(PowerShell)

パワーシェルには入力をマスクするオプションが用意されているので楽ちんです。

$inputPass = read-host 'パスワード=' -AsSecureString ;

「read-host」コマンドにオプションとして「-AsSecureString」をつければ自動的に入力を「*」に変換してくれます。入力結果はそのまま「$inputPass」に格納されます。

マスクされた文字列を元に戻す

$inputPassの中身はそのままでは解読できないデータが入っています。
そのため、一度元のデータに戻す必要があります。

$BSTR=[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($inputPass);
[System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)

「SecureStringToBSTR」は()内のデータを復元するコマンドです。
これを行うことで、「$BSTR」にちゃんと読めるデータを格納しています。

「PtrToStringAuto」は出来上がったデータを読み出すコマンドで、実行すると()内の値を出力してくれます。

※[System.Runtime.InteropServices.Marshal]はメモリ上のデータを操作するためのものです。
かなり色んなことができるのですが、ここでは割愛します。

復元された文字列をバッチに渡す

最後にバッチ側で出力された値を読み込みます。
PowerShellの結果を読み込むには「for」を使った形で読み込んであげるのが一般的です。

for /f "tokens=*" %%a in ('%pscmd%') do set PASSWORD=%%a

「'」でくくられたコマンドを実行して、「%%a」に格納する形です。
最初に%pscmd%の中にパワーシェルコマンドを入れておいたので、コードがすっきりしていますね。

あとがき

今回は、入力した文字を「*」にマスクする方法を紹介させていただきました。

正直、バッチファイルで入力がマスクできないのは非常に困ります。
再起動を挟むバッチなどでは、必ずログイン画面という壁があるからですね。
共有サーバーにアクセスする際なども使います。

ユーザーに入力してもらえば済む話ですが、自動でやりたいですよね。だって放置しておけば処理が完了するほうが確実ですもの。(ユーザーが入力ミスする可能性もありますし・・・。

ショルダーハッキングしかり、いくらエンジニア側が対策を取ったとしても漏れてしまう情報はたくさんあります。
パソコンのセキュリティが万全だと安心せず、「家に鍵をかける」や、盗まれたら換金されてしまうような「金目のものを出しっぱなしにしない」などの物理的なセキュリティも気にしていきたいですね。

魔が差すという言葉があるくらいですから、そんな誘惑をさせない振る舞いはITに関わらず大事なことだと思いますね。

おまけ

入力を2回行って正しいか確認してから処理を進めるコード

@echo off
:input

set "pscmd=powershell.exe -Command " ^
$inputPass = read-host 'パスワード=' -AsSecureString ; ^
$BSTR=[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($inputPass); ^
[System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)""

for /f "tokens=*" %%a in ('%pscmd%') do set PASSWORD=%%a

set "pscmd=powershell.exe -Command " ^
$inputPass = read-host 'もう一度入力してください=' -AsSecureString ; ^
$BSTR=[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($inputPass); ^
[System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)""

for /f "tokens=*" %%a in ('%pscmd%') do set PASSWORD_C=%%a

if %PASSWORD% neq %PASSWORD_C% (
   echo 入力が間違っています
   pause
   cls
   goto :input
)

echo 入力OK
pause

非常に単純に2回別の変数に入力を格納して比較しています。
間違っていたら画面をクリアした後に「:input」にジャンプさせ、OKならそのまま先に進む形ですね。

なにかのお役にたてれば幸いです。

参考サイト

Powershellでパスワード入力 - Qiita
PowerShellで簡単なパスワード入力方法と入力した文字の確認する仕方を調べたので、記載します。###PowerShellでパスワード入力と入力文字の確認$secstr = Read-Ho…
Marshal クラス (System.Runtime.InteropServices)
アンマネージド コードを扱うときに使用できるさまざまなメソッドを提供します。これらのメソッドを使用すると、アンマネージド メモリの割り当て、アンマネージド メモリ ブロックのコピー、マネージド型からアンマネージド型への変換などができます。

ありがとうございます!

コメント

Translate »
タイトルとURLをコピーしました