Время прочтения: 5 мин.
Друзья, хочу поделиться с вами опытом решения одной из задач, поставленной передо мной в процессе аудита. Мне требовалось подтвердить или опровергнуть предположение о нарушении технологии обработки данных в автоматизированной системе, а именно: проверить содержимое каталогов, размещенных на FTP-сервере, на наличие в них определенных файлов.
Для решения данной задачи я использовал Python и его стандартный модуль ftplib.
Опишу, как я это сделал. Для того, чтобы у вас была возможность попробовать самостоятельно проверить работу кода, я опишу процесс на примере FTP-сервера Ростовского госуниверситета (ftp.rsu.ru).
Итак, начнем. Импортируем необходимые модули:
import ftplib
import os
from datetime import datetime
Для входа на FTP-сервер потребуется указать учетные данные (имя пользователя и пароль), а в случае возможности входить анонимно (это наш случай в приводимом для примера FTP-сервере) используем следующие строки:
FTP_HOST = 'ftp.rsu.ur'
FTP_USER = 'anonymous'
FTP_PASS = ''
Далее используем вспомогательные функции, которые позволят вывести список «найденных» каталогов и файлов:
# некоторые служебные функции, которые нам понадобятся
def get_size_format(n, suffix='B'):
# преобразует байты в масштабированный формат (KB, MB, и т.д.)
for unit in ['', 'K', 'M', 'G', 'T', 'P']:
if n < 1024:
return f'{n:.2f}{unit}{suffix}'
n /= 1024
def get_datetime_format(date_time):
# преобразовать в объект даты и времени
date_time = datetime.strptime(date_time, '%Y%m%d%H%M%S')
# преобразовать в удобочитаемую строку даты и времени
return date_time.strftime('%Y/%m/%d %H:%M:%S')
Затем подключаемся к серверу, используя класс клиента FTP:
# инициализировать сеанс FTP
ftp = ftplib.FTP(FTP_HOST, FTP_USER, FTP_PASS)
Для исключения проблем при работе с нелатинскими символами, изменим кодировку на UTF-8 :
# принудительное кодирование UTF-8
ftp.encoding = 'utf-8'
Теперь, когда мы получили доступ к серверу, выведем приветственное сообщение, которое отправляется сервером после подключения (для уверенности, что мы оказались там, где надо 🙂
# вывести приветственное сообщение
print(ftp.getwelcome())
Вот оно!
220 ProFTPD 1.3.5b Server (FTP Server of Rostov State University — only anonymous logins are allowed) [195.208.245.253]
После подключения к серверу мы находимся в корневом каталоге. Посмотрим на его содержимое, используя команду MLSD, с помощью которой получаем список каталогов и файлов с их метаданными: разрешение, размер, дата последней модификации и т. д.
print('*'*50, 'MLSD', '*'*50)
# используем команду MLSD
print('{:30} {:19} {:6} {:5} {:4} {:4} {:4} {}'.format('File Name', 'Last Modified', 'Size',
'Perm', 'Type', 'GRP', 'MODE', 'OWNER'))
for file_data in ftp.mlsd():
# извлечь возвращаемые данные
file_name, meta = file_data
# т.е. каталог, файл или ссылка и т. д.
file_type = meta.get('type')
if file_type == 'file':
# если это файл, изменить тип передаваемых данных на IMAGE / binary
ftp.voidcmd('TYPE I')
# получить размер файла в байтах
file_size = ftp.size(file_name)
# преобразовать его в удобочитаемый формат (т. е. в «КБ», «МБ» и т. д.)
file_size = get_size_format(file_size)
else:
# не файл, то может быть каталог
file_size = 'N/A'
# дата последней модификации файла
last_modified = get_datetime_format(meta.get('modify'))
# права доступа к файлу
permission = meta.get('perm')
# получить id файла
unique_id = meta.get('unique')
# группа пользователей
unix_group = meta.get('unix.group')
# файловый режим, разрешения Unix
unix_mode = meta.get('unix.mode')
# владелец файла
unix_owner = meta.get('unix.owner')
# вывод результата
print(f'{file_name:30} {last_modified} {file_size:7} {permission:5} {file_type:4} {unix_group:4} {unix_mode:4} {unix_owner}')
Вот результат работы команды MLSD:
************************************************** MLSD **************************************************
File Name Last Modified Size Perm Type GRP MODE OWNER
. 2020/02/14 11:51:40 N/A fle cdir 35901 0644 0
.. 2020/02/14 11:51:40 N/A fle pdir 35901 0644 0
docsvisionclient 2016/08/01 13:36:22 N/A fle dir 35901 0644 37411
terminal 2011/09/24 18:22:19 N/A fle dir 35901 0644 0
Edu_tools 2011/09/24 18:23:15 N/A fle dir 35901 0644 0
Solaris 2020/03/31 21:15:57 N/A fle dir 35901 0644 0
net 2012/01/27 14:16:46 N/A fle dir 35901 0644 0
fujitsu 2017/09/11 14:32:06 N/A fle dir 35901 0644 0
security 2012/01/27 14:22:14 N/A fle dir 35901 0644 0
hardware 2011/09/24 18:15:29 N/A fle dir 35901 0644 0
development 2012/01/27 14:02:03 N/A fle dir 35901 0644 0
archivers 2011/09/24 18:38:42 N/A fle dir 35901 0644 0
databases 2012/01/27 13:59:13 N/A fle dir 35901 0644 0
telephony 2011/09/24 18:26:25 N/A fle dir 35901 0644 0
desktop 2013/12/05 18:12:14 N/A fle dir 35901 0644 0
video 2014/03/12 08:32:36 N/A fle dir 25512 0644 35422
media 2011/09/24 18:19:13 N/A fle dir 35901 0644 0
publishing 2012/01/27 14:20:54 N/A fle dir 35901 0644 0
shells 2011/09/24 18:19:33 N/A fle dir 35901 0644 0
linux 2018/04/20 05:22:10 N/A fle dir 35901 0644 0
local 2011/09/24 18:04:29 N/A fle dir 35901 0644 0
bacula 2015/09/21 08:00:37 N/A fle dir 35901 0644 35428
ccm 2011/09/24 18:21:47 N/A fle dir 35901 0644 0
patches 2014/08/11 18:26:39 N/A fle dir 35901 0644 0
gparted 2014/09/16 12:06:29 N/A fle dir 35901 0644 0
public 2013/06/07 13:11:38 N/A adfr OS.unix=symlink 35901 0644 0
office 2012/01/27 14:17:31 N/A fle dir 35901 0644 0
text 2011/09/24 18:19:33 N/A fle dir 35901 0644 0
sysutils 2011/09/24 18:22:36 N/A fle dir 35901 0644 0
FreeBSD 2020/02/14 12:07:50 N/A fle dir 0 0644 0
Далее, если потребуется сменить текущий каталог на какой-либо другой, например pub/maps, чтобы проверить его содержимое, используем команду cwd:
# изменить текущий рабочий каталог на каталог «pub» и подкаталог «maps»
ftp.cwd("linux/debian")
Если все ОК, получим сообщение:
‘250 CWD command successful’
Теперь можно повторить выполнение MLSD и вот содержимое ее работы
************************************************** MLSD **************************************************
File Name Last Modified Size Perm Type GRP MODE OWNER
. 2020/05/13 10:51:46 N/A fle cdir 35901 0644 0
.. 2018/04/20 05:22:10 N/A fle pdir 35901 0644 0
firmware-10.4.0-amd64-DVD-1.iso 2020/05/09 12:00:00 3.69GB adfr file 0 0644 0
firmware-9.3.0-amd64-DVD-1.iso 2017/12/09 13:09:55 3.39GB adfr file 35901 0644 0
debian-7.6.0-amd64-CD-1.iso 2014/09/09 07:48:00 635.00MB adfr file 35901 0644 44185
ql.iso 2015/06/11 08:35:21 602.00KB adfr file 1000 0644 1000
firmware-qlogic_20190717-2_all.iso 2020/05/13 10:51:46 3.38MB adfr file 0 0644 0
debian-8.4.0-amd64-CD-1.iso 2016/04/02 16:06:34 630.00MB adfr file 35901 0644 0
firmware.iso 2020/05/13 10:34:11 4.22MB adfr file 35901 0644 39622
После окончания работы с FTP-сервером закрываем соединение:
# выйти и закрыть соединение
ftp.quit()
В результате: '221 Goodbye.'
Вот так, используя этот код, я получил возможность судить о наполнении каталогов информацией, чтобы затем сделать выводы о том, выполняются или нет требования нормативных документов компании в части полноты сохраняемых данных в виде файлов, их корректности наименования и размещения в определенных каталогах FTP-сервера.