⛰️

PythonでJSON中の特定文字をユニコードエスケープする

2022/06/16に公開

はじめに

特にWebシステムとかユーザー入力したものを出力したりする場合に関係が深いのだろうが、
XSS対策の一つでJSON内の要素に動的に文字列を出す場合は以下のような特殊記号をユニコードエスケープシーケンス(\u00XX)に変換するようにと、セキュリティ診断サービスなどで警告を受ける場合がある。そんな場合に利用したい処理となる。ユニコードエスケープをしても、受け取り側で戻された後にブラウザ上でJavaScript評価されてしまうと意味ないので、html.escape()も考慮すべきかと思う。

なお、ResponseBodyに対して上記のような対策を行うと共に、
ResponseHeaderにも以下を参考に設定を行うと良い。
AWSドキュメントより - レスポンスにセキュリティヘッダーを追加する

実装(Python3.9)

今回JSONを文字列で返却したかったのだが、
dictを最後はjsonのdumpsを利用して文字列として返却したかったため、
単純な文字列をエスケープするものと、dictの文字列型の値のみをエスケープ処理するものを用意した。

文字列の変換処理

import re

# エスケープ対応したい任意の文字を入れて、プリコンパイル
escape_re_pattern = re.compile(r'([\'\"<>&\\])', flags=re.I)

def escape_str(target: str) -> str:
    excaped = escape_re_pattern.sub(
	lambda m: f'\\u{ord(m.group(0)):04x}', target)
    return escaped

dictの文字列要素の変換処理

def excape_dict_str_value(target: dict[str, any]) -> dict[str, any]:
    return {k: excape_str(v) if isinstance(v, str) else v 
	    for k, v in target.items()}

自分はPython初心者なので、内包表記という呼び名を初めて知ったが、とても便利だと思った。
あとは、三項演算子も一緒に利用している。

利用方法としては以下。

import json

target = {
    'a': 'あああ',
    'i': '胃位イ',
    'u': 'abc\'def\"abc<def>abc&def\\abc',
    'e': 12345,
    'o': True
}

json.dumps(escape_dict_str_value(target))

最後に

もっと良い処理がある。
他のライブラリなどを用いたほうが楽だ。
などがありましたら是非教えて下さい。

Discussion