概要
仕事で、VBAのプログラムを引き継ぐということがあったのですが、そのプログラムが関数のスコープを意識せずに設計されていたらしく、脆弱性があることが分かりました。
正直、私も、変数はともかく関数のスコープまでちゃんと意識していない人間だったので、今後、同じことを私が行わないように、ちゃんとアウトプットしておくことにしました。
どんなプログラムだったの?
どのようなプログラムだったかというと、以下の画像のシートとコードがあるExcelファイルであり、「admin」ボタンを押すとパスワードの入力を求められ、パスワードがあっていると「見られちゃいけないシート」が見れるようになるというプログラムだった。
パスワードを直接書いているとか、いろいろ突っ込みどころはあるのですが、おそらく初心者の人に予想外の操作をされたくないための設定なので、とりあえず無視しておきます、今回はそのことではなくスコープについてです。
Option Explicit
Sub admin()
Dim ans As String
ans = InputBox("パスワード", "パスワード", "")
If ans = "12345" Then
Call Visible
Else
MsgBox "パスワードが違います。"
End If
End Sub
Sub Visible()
Sheet2.Visible = xlSheetVisible
End Sub
Sub VeryHidden()
Sheet2.Visible = xlSheetVeryHidden
End Sub
スコープをちゃんとしないと起こること
VBAには関数や変数を宣言する前にprivateとpublicを宣言することができます。
privateと宣言された場合は宣言したモジュールの中でのみで使用できるようになり、publicと設定された場合はプロジェクト全体の中で見ることができます。
そして何も宣言しないと変数や関数はpublicに設定されるようになっているため、たとえば、ボタンにマクロの登録をしようとすると、シートを見せる関数「VeryHidden」が設定可能になっていることが分かります。
このままでは、「見られちゃいけないシート」が簡単にみられてしまいますし、標準モジュールにパスワードをかけたとしても、だれでもボタンに登録するマクロを別のものに変えることができ、初心者の方に予想外の操作を行われる危険性があります。
Functionというパラメータを設定した場合にも、セルに関数名を入力すると、以下のように実行できてしまう。
この場合、マクロが行うワークブックに対しての処理(ThisWorkbook.Closeなど)は無視されるようですが、こんなに簡単に実行できてしまうと、初心者の人がやらかしかねないので、実行できないようにしておくのが望ましいでしょう。
Function MoveMe(num As Long)
If num = 0 Then
MsgBox "表示されました"
End If
End Function
解決策
先ほど出てきましたが、privateを設定するだけで、簡単には見れなくなります。
以下のコードのように、見せていい関数はPublic、見せたくない関数はPrivateを設定することで、先ほどのように簡単に実行できてしまうということは起こりません。
Public Sub admin()
Dim ans As String
ans = InputBox("パスワード", "パスワード", "")
If ans = "12345" Then
Call Visible
Else
MsgBox "パスワードが違います。"
End If
End Sub
Private Sub Visible()
Sheet2.Visible = xlSheetVisible
End Sub
Private Sub VeryHidden()
Sheet2.Visible = xlSheetVeryHidden
End Sub
Private Function MoveMe(num As Long)
If num = 0 Then
MsgBox "表示されました"
End If
End Function
ただし見れなくなっただけで、「マクロ名」に実行したい関数名を入力すると、実行自体はできてしまうようです、あくまで簡単に見れなくなるだけです。(Privateとは一体…)
関数名がばれてしまったら、もうあきらめましょう。
まとめ
VBAでもスコープをちゃんと設定しないと、予想外の操作が行えてしまうことの説明と解決策についてまとめました。
ただし、Excel自体、セキュリティ関連が弱いので、詳しい人ならばパスワードをかけようが簡単に解読できてしまいます、VBAは個人で使うだけにするのがいいのかもしれません。