- WSOFT Docs
- ブログ
- 共同作成ガイド
-
製品
- 製品
- PCMX
- WSOFTアカウント
- AliceScript
- AliceScript
- 謝辞
- ダウンロード
- Alice(キャラクター)
- AliceScriptのツアー
- Wikiの概要
- APIブラウザー
- APIブラウザー
- Alice
- break
- continue
- delay
- do
- exit
- for
- foreach
- function
- if
- import
- include
- lock
- read
- return
- string_format
- switch
- using
- while
- write
- Diagnostics
- Environment
- env_clr_version
- env_commandLine
- env_commandLineArgs
- env_set_exitCode
- env_expand_environmentVariables
- env_get_environmentVariable
- env_hasShutdownStarted
- env_impl_architecture
- env_impl_location
- env_impl_name
- env_impl_target
- env_impl_version
- env_Is64BitOperatingSystem
- env_Is64BitProcess
- env_MachineName
- env_NewLine
- env_os_platform
- env_os_version
- env_set_environmentVariable
- Exception
- Interpreter
- gc_collect
- gc_collectAfterExecute
- gc_getTotalMemory
- interpreter_append_output
- interpreter_append_output
- interpreter_consts
- interpreter_namespaces
- interpreter_getVariable
- interpreter_globalVariables
- interpreter_name
- interpreter_nameexists
- interpreter_namespaces
- interpreter_process
- interpreter_processfile
- interpreter_reset_variables
- Type
- Math
- math_abs
- math_acos
- math_acosh
- math_atan
- math_atan2
- math_atanh
- math_bitdecrement
- math_bitincrement
- math_cbrt
- math_celling
- math_clamp
- math_copysign
- math_cos
- math_cosh
- math_e
- math_exp
- math_factorial
- math_floor
- math_fusedmultiplyadd
- math_isFinite
- math_isInfinity
- math_isNaN
- math_isNegativeInfinity
- math_isNormal
- math_isPositiveInfinity
- math_isprime
- math_isSubNormal
- math_max
- math_min
- math_pi
- math_pow
- math_round
- math_sin
- math_sinh
- math_sqrt
- math_tan
- math_tanh
- math_tau
- math_truncate
- Net
- Parsing
- Random
- Security
- Threading
- Array
- Bool
- Bytes
- Delegate
- None
- Number
- String
- string
- CompareTo
- Contains
- EndsWith
- Equals
- Format
- GetBytes
- Indent
- IndexOf
- Insert
- IsEmptyOrNull
- IsEmptyOrWhiteSpace
- IsNormalized
- Join
- LastIndexOf
- Normalize
- PadCenter
- PadLeft
- PadRight
- Remove
- RemoveAt
- Repeat
- Replace
- ReplaceLineEndings
- Split
- SplitLines
- StartsWith
- SubString
- ToLower
- ToLowerInvariant
- ToUpper
- ToUpperInvariant
- Trim
- Trim
- TrimStart
- Variable
- 変更履歴
- 例外
- 例外
- 0x000 NONE
- 0x001 COULDNT_FIND_FUNCTION
- 0x003 INVALID_OPERAND
- 0x004 COULDNT_FIND_VARIABLE
- 0x005 ITS_RESERVED_NAME
- 0x006 ILLEGAL_IDENTIFIER
- 0x009 INCOMPLETE_ARGUMENTS
- 0x01a COULDNT_ADD_PARAMETERS_AFTER_PARMS_KEYWORD
- 0x020 COULDNT_EXECUTE_BLOCK
- 0x021 NEED_BRACKETS
- 0x022 UNNEED_TO_BRACKETS
- 0x04a CASE_BLOCK_MISSING_BREAK
- 0x04b UNKNOWN_ESCAPE_CHAR
- 基本
- Alice in Discord
- 相互運用
- チュートリアル
- ダウンロードセンター
- ほめて.ws
- アイコンメーカー
- WSOFTScript
- Unidet
- WebSailing
- WSNET
- WSTodon
- WSTube
- Lantana
- 法的資料
-
あみうは
- あみうは
- 新学期が始まりました!
- 恋の相談
- プチコン3号で作ったのは?
- オススメの文庫
- マクドナルド最高!
- ios11β レビュー
- あみうはの歌について
- ついに自分のソフトウェアのホームページができました。
- Windowsタブレットをリセットして起動しなくなった人のために
- PCレスで YouTubeの曲を携帯mp3プレイヤーで聴く(iPhone)
- 食べられないラズベリーパイを買いました。(1)
- ラズベリーパイの下ごしらえ(2)
- 小説始めます~
- 女子がキュンとくる行動ベスト3!!
- MacとWindowsについてあまり知られていない事
- macでできる裏技
- ドコモの格安スマホ「MONO」買っちゃいました☆いい所をいくつか
- 『レビュー』iPhone6sを1年間使い続けて思ったこと
- iPhoneの拡大鏡に関するバクを発見しました。
- iPhoneで圧縮ファイルを作成したり解凍する方法
- Obscura2が今だけ無料!使い方まとめ
- Windowsタブレットがブルースクリーンになった時のメモ
- お知らせ
AliceScriptで安全にパスワードを保存する
この記事ではAliceScriptのライブラリを使用して安全にパスワードを保存する方法について説明します。
ログインなどの認証機構を実装するとき、どうしても何らかの形でユーザー情報を保存する必要があります。
このとき、もしパスワードを平文でファイルに保存していたとしたら、どうなるでしょうか。 万が一、悪意のあるユーザーにファイルアクセスを許してしまった場合、パスワードが盗まれシステムに不正にアクセスできてしまいます。
また、パスワードは複数のシステムで使いまわす人も少なくありませんから、そのシステムだけでなく、よそのシステムにも不正にログインされてしまう恐れがあります。
このような理由から、パスワードをそのまま保存してはいけません。この記事ではパスワードの安全な保管方法を、実際にAliceScriptを用いて説明します。
パスワードのハッシュを保存する
まず、パスワードは保存しない、ということが重要です。
パスワードは保存せず、認証するのに十分な情報だけを保存し、さらにその情報から元のパスワードを推測されないようにするとういう方針が、基本的な考え方です。
しかし、「ユーザー認証の際にパスワードを確認する」ことと、「パスワードを保存しない」ことは両立できるでしょうか?答えはYesです。方法はあります。パスワードではなく、パスワードのハッシュを保存すればよいのです。
ハッシュ関数とは何でしょうか?たとえば下の式は、簡単な一次関数です。この関数には、ある決まった数\(x\)と定数\(a\)を与えてやれば、決まった値\(y\)が出力されます。 $$ \operatorname{hash} y = ax (aは定数) $$
たとえばあなたの設定したパスワードが1234
だとしましょう。パスワードを保存するときにそのまま保存するのではなく、\(a=75\)を与えて関数\(hash\)に代入し、その値を保存します。すると、結果は次のようになります。
元のパスワード | 関数の結果 |
---|---|
1234 | 92550 |
次に攻撃者の側に立ってみます。データセンターにハッキングしたあなたは、password.txt
というファイルを運よく見つけました。そこには92550
という数値が書いてありました。やりました!パスワードを見つけたのです。早速そのパスワードでログインしてみると、どういうわけかログインできません。攻撃者は先ほど決めた\(\operatorname{hash} y = ax (aは定数)\)と、\(a=75\)を使ってパスワードが保存されていることを攻撃者は知らなかったからです。
しかしこのハッカー、パスワードがハッシュ化されて保存されていることに気付きました。運よくデータセンターにアクセスしていることはバレていないので、ハッカーはいろいろとパスワードを登録して、どのように保存されているかを調べました。
元のパスワード | 保存されているパスワード |
---|---|
1234 | 92550 |
1235 | 92564 |
1236 | 92700 |
この表を見れば、パスワードが\(\operatorname{hash} y = ax (a=75)\)に通されていることは明らかです。そこで今度は新しいハッシュ化の方法を考えました。次の式で\(b\)は毎回変わり、性懲りもなく\(a=75\)とします。 $$ \operatorname{hash} y = a(x+b)^2 (aは定数、bは変数) $$
ハッカーが来ました。ハッシュ関数が変わったらしい、という噂は聞いているので、小手調べにパスワードをいろいろ登録して、保存されている値を調べました。
元のパスワード | 保存されているパスワード |
---|---|
1234 | 21242881 |
1235 | 6300100 |
元のパスワードと保存されているパスワードに規則性が見出せません。どうやらハッシュ関数は推測できなさそうです。運営側の勝利に終わったのには、毎回変わる変数\(b\)を定めていたからです。これが、ソルトです。
元のパスワード | 保存されているパスワード | \(b\)の値 |
---|---|---|
1234 | 21242881 | 45 |
1235 | 6300100 | 17 |
ええ、実際にはもっと難しいアルゴリズムがあります。たとえば\(a\)には、ものすごく大きい素数\(p\)を代入していたりします。それはさておき、このように、パスワードとハッシュ関数、ソルトを用いてパスワードを安全に保存することに成功しました。
ソルトの生成
安全にパスワードを保存するためには、ソルトの値も安全である必要があります。安全な値というのは簡単に人間の頭で思いついては困りますから、コンピューターに計算させましょう。AliceScriptではpassword_getSalt
関数で簡単にソルトを生成できます。
パスワードのハッシュ化
ソルトができたら、実際にパスワードをハッシュ化してみましょう。password_hash
関数でパスワードをハッシュ化できます。password
はもちろん、推測されにくいパスワードを使ってください。
パスワードの検証
パスワードはハッシュ化できたので、実際にパスワードを検証してみましょう。password_verify
関数はパスワードか正しければtrue
が、間違っていればfalse
が返ります。
まとめ
まとめとして、実行するたびにパスワードを求め、認証に成功したらパスワードの変更を促して終わるプログラムを作成します。
using Alice.IO;
using Alice.Security;
using Alice.Console;
const HASH_FILE_NAME = "user_data.bin";
const SALT_FILE_NAME = "user_sub.bin";
function checkExistsData()
{
return file_exists(HASH_FILE_NAME) && file_exists(SALT_FILE_NAME);
}
function changePassword()
{
print("新しいパスワードを入力してください。");
var passwd = console_readline();
var salt = password_getSalt();
var hash = password_hash(passwd,salt);
file_write_data(HASH_FILE_NAME,hash);
file_write_data(SALT_FILE_NAME,salt);
print("パスワードを保存しました。終了します。");
exit;
}
function login()
{
print("パスワードを入力してください。");
var passwd = console_readline();
var salt = file_read_data(SALT_FILE_NAME);
var hash = file_read_data(HASH_FILE_NAME);
if(password_verify(passwd,salt,hash)){
print("ログインに成功しました。");
changePassword();
return;
}
print("ログインに失敗しました。終了します。");
exit;
}
if(checkExistsData()){
login();
}else{
changePassword();
}
実行してみると、「新しいパスワードを入力してください。」とパスワードの作成を求められ、作成すると、次回からの起動にそのパスワードが必要になります。パスワードのハッシュとソルトはそれぞれ、user_data.bin
とuser_sub.bin
に保存されています。盗まれないようにしてください。