0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

今さらawkでメタ文字エスケープ、コマンドインジェクション対策

Last updated at Posted at 2020-07-16

メタ文字(エスケープシーケンス)をawkでエスケープする

目的

  • LATS(Linux Apache Textfile and Script)でWEBアプリを作っています。
  • セキュリティ向上のためHTMLから悪意のある文字列入力がであってもサーバで実行できないようににしたいと思いました。
  • 具体的にはダイレクトOSコマンドインジェクションやディレクトリトラバーサルとか呼ばれる攻撃を避けようと思いました。
  • rubyにはescapeHTML()があり

与えられた文字列中の '、&、"、<、> を実体参照に置換した文字列を新しく作成し返します。

とあります。

  • phpにも HTML特殊文字をエスケープする htmlspecialchars()があります。

  • 今回はサーバサイドつまりscriptでHTMLの制御文字だけでなく、メタ文字(エスケープシーケンス)をHTMLの文字実体に変換することを考えます。クライアントサイトでは比較的に簡単に検索できました。でもBrowserだけでなく、curlなどでも攻撃がありえるのでJavaScriptだけでなく、サーバサイドでの対策します。

クライアントサイド(JavaScript)の例

実験

  • Shell Scriptではsedとかawkとかが思いつきます。それで実験してみます。
$ echo '!' | sed -e 's|!|\&#33;|g'                                                                                                                                                                                                                                      
&#33;   

とうまくいきそうです。でも2つ以上-eの変換コマンドを続けるとうまくいきません。

$ echo '!' | sed -e 's|!|\&#33;|g' -e 's|\&|\&#63;|g'                                                                                                                                                                                                                   
&#63;#33; 

これはsedが一つ目の-eで置換した結果に対して2つ目の-eを適用するためです。一つ目の変換された&が2つ目の-eでさらに変換されたのです。
awkも次の構文ではうまくいきません。

$ echo '!' | awk '{gsub("!","\\&#33;",$0); gsub("&","\\&#63;",$0);print}'                                                                                                                                                                                               
&#63;#33;

sedと同じく、一つ目のgsub()$0を書き換えるため、二つ目のgsub()でそれを変換するためです。それではどうしましょうか。お風呂に入っていて思いつきました。

考え方とテスト

  • 文字毎に変換したら終わりのスクリプトにすればいいです。そのため、文を文字に分解して、分解された文字がメタ文字と一致したら一度だけ変換しおしまいにします。
  • ツールは万能awkを使いましょう。文字毎に変換はfold -w 1でもできますが、パイプで渡すくらいならawkだけで処理しましょう。文字列分解の参考はこちらgawk FS=''で文字分解できました。MacOSのawkではNGでした。
$ cat escapeHTML.bash
#!/usr/bin/env bash
gawk -v FS='' '{
 for (i = 1; i <= NF; i++) {
  if(       $i == "!" ) { printf "&!#34;" 
  }else if( $i == "?" ) { printf "&#63;"
  }else if( $i == "&" ) { printf "&#38;"
  }else if( $i == "#" ) { printf "&#35;"
  }else {printf "%s", $i}
 }
}'        
$ echo '!' | ./escapeHTML.awk                                                                                                                                                                                                                                           
&!#34;

いい感じです。長い文字列も試してみましょう。

$ echo '12345!?&#あいうえお' | ./escapeHTML.bash
12345&!#34;&#63;&#38;&#35;あいうえお

うまくいっています。テストコードですがご参考まで。もっといい方法があったら教えてください。

参考

数字参照

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?