読者です 読者をやめる 読者になる 読者になる

仕事中の問題と解決メモ。

最近はPythonとGoogle Cloud Platformがメイン。株式会社ビズオーシャンで企画と開発運用、データ活用とか。 http://mstdn.bizocean.co.jp/@uyamazak https://github.com/uyamazak/

Python3でipaddressモジュールを使って、IPアドレス認証を行う

本番環境のWEBアプリケーションで、デバッグ情報を表示させる際、サーバー情報なども全部さらけだすので、最低限IP認証だけ行いたいと思った。

IPアドレスの文字列比較なら簡単だけど、できればネットワークアドレス(192.168.0.0/24等)で許可できると便利。

検索した所、python3からは標準でipaddressというモジュールがあるのを知った。Googleが作ったipaddrが元になってるらしい。

21.28. ipaddress — IPv4/IPv6 操作ライブラリ — Python 3.5.2 ドキュメント


下記のような感じで書いてみた。

許可するIPのリスト名はDjangoのsettings.pyから取った。

strでカンマ区切りで指定して後で分割する。

import ipaddress

INTERNAL_IPS_V4 = "192.168.0.0/16,127.1.1.1"


def is_internal_ip(client_ip_str) -> bool:
    internal_ip_list = INTERNAL_IPS_V4.split(",")
    client_ip = ipaddress.ip_address(client_ip_str)
    for internal_ip in internal_ip_list:
        ip_network = ipaddress.ip_network(internal_ip)
        if client_ip in ip_network:
            return True

    return False

ipaddress.ip_networkは、/なしで普通のIPアドレスを指定すると/32があるとして良しなにしてくれるので、IPアドレスとネットワークアドレスが一緒でも問題なく動いた。

>>> is_internal_ip("192.168.50.1")
True
>>> is_internal_ip("192.167.50.1")
False
>>> is_internal_ip("127.1.1.1")
True
>>> is_internal_ip("127.1.1.2")
False
>>> is_internal_ip("127.1.2.1")
False
>>> is_internal_ip("255.255.255.0")
False
>>> is_internal_ip("192.168.277.777")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/oceanus/app/common/utils.py", line 77, in is_internal_ip
    client_ip = ipaddress.ip_address(client_ip_str)
  File "/usr/local/lib/python3.6/ipaddress.py", line 54, in ip_address
    address)
ValueError: '192.168.277.777' does not appear to be an IPv4 or IPv6 address


そもそも与えられたclient_ip_strがIPアドレスとして正しいかは見ていないので、変なの入れるとエラーが出るけど、自分で設定するんだから大丈夫だよね。

入門 Python 3

入門 Python 3