Любое приложение, которое хоть как‑то работает с сетью, должно валидировать правильность IP-адресов. Это сложнее, чем может показаться. Здесь легко впасть в крайности: при излишне строгой валидации пользователь не сможет ввести верные данные, при недостаточной — окажется наедине с низкоуровневыми сообщениями об ошибках (если они вообще передаются). В этой статье мы разберем ряд сложностей, возникающих при валидации адресов, а потом посмотрим на готовые библиотеки, которые с этим помогают.
Ошибки в адресах могут появиться тремя способами:
От попыток сломать приложение одна валидация адресов не поможет. Она может затруднить такие попытки, но не заменит полноценную проверку авторизации и обработку ошибок на всех этапах работы программы, так что улучшение безопасности нужно рассматривать скорее как полезный побочный эффект. Основная цель — упростить жизнь пользователям, которые случайно ввели неверный адрес или неправильно поняли, что от них требуется.
Проверки можно условно разделить на проверки по форме и по существу. Цель формальной проверки — убедиться, что введенная пользователем строка вообще может быть допустимым адресом. Многие программы ограничиваются именно этим. Мы же пойдем дальше и посмотрим, как можно проверять, что адрес не только правильный, но и подходящий для конкретной цели, но об этом позже.
Проверка правильности формата только на вид может показаться задачей для несложного регулярного выражения — на деле все не так просто.
В IPv4 сложности начинаются со стандарта на этот формат — такого стандарта не существует. Формат dot-decimal (0.0.0.0–255.255.255.255
) — общепринятый, но не стандартный. Стандарт IPv4 не содержит никаких упоминаний о формате записи адресов вообще. Никакой другой RFC тоже ничего не говорит о формате адресов IPv4, так что общепринятый формат — это не более чем соглашение.
И это даже не единственное соглашение. Функция inet_aton()
позволяет не писать нулевые разряды в конце адреса, например 192.0.2 = 192.0.2.0
. Кроме того, она позволяет вводить адрес одним целым числом, 511 = 0.0.1.255
.
Может ли адрес хоста заканчиваться на ноль? Конечно, может — в любой сети размером больше /23 найдется хотя бы один такой. Например, 192.168.0.0/23
содержит адреса хостов 192.168.0.1–192.168.1.254
, включая 192.168.1.0
.
Если ограничиться поддержкой только полного dot-decimal из четырех групп, без возможности опускать нулевые разряды, то выражение (d+).(d+).(d+).(d+)
может поймать значительную часть опечаток. Если задаться целью, можно составить выражение для любого допустимого адреса, хотя оно и будет довольно громоздким. Лучше воспользоваться тем, что его легко разделить на группы, и явно проверить, что каждая из них попадает в диапазон 0–255:
def check_ipv4(s): groups = s.split('.') if len(groups) != 4: for g in groups: num = int(g) if (num > 255) or (num < 0): raise ValueError("Invalid octet value")
С IPv6 все одновременно проще и сложнее. Проще потому, что авторы IPv6 учли опыт IPv4 и добавили формат записи адресов в RFC 4291. О любых альтернативных форматах можно смело говорить, что они против стандарта, и игнорировать. С другой стороны, сами форматы сложнее. Основную сложность представляет сокращенная запись: группы нулевых разрядов можно заменять на символ ::
, например 2001:db8::1
вместо 2001:db8:0:0:0:0:0:1
. Для пользователя это, безусловно, удобно, но для разработчика все ровно наоборот: разделить адрес на группы по двоеточию невозможно, нужна заметно более сложная логика. К тому же стандарт запрещает использовать ::
больше одного раза в одном адресе, что еще сильнее усложняет задачу.
Так что, если приложение поддерживает IPv6, для валидации адресов нужен полноценный парсер. Писать его самим нет смысла, поскольку существуют готовые библиотеки, которые предоставляют и другие полезные функции.
Если уж мы взялись подключать библиотеку и парсить адреса, давай посмотрим, какие дополнительные проверки мы можем провести, чтобы отсеять ошибочные значения и сделать сообщения об ошибках более информативными.
Материалы из последних выпусков становятся доступны по отдельности только через два месяца после публикации. Чтобы продолжить чтение, необходимо стать участником сообщества «Xakep.ru».
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее
1 год8460 р. |
1 месяц790 р. |
Я уже участник «Xakep.ru»
Читайте также
Последние новости