
Pequena biblioteca Python que facilita a exploração de condições de corrida em aplicações web com Requests.
Requests-Racer é uma pequena biblioteca Python que permite usar a biblioteca Requests para enviar múltiplas requisições que serão processadas por seus servidores de destino aproximadamente ao mesmo tempo, mesmo que as requisições tenham destinos diferentes ou tenham payloads de tamanhos diferentes. Isso pode ser útil para detectar e explorar vulnerabilidades de condição de corrida em aplicações web. (Para mais informações, veja motivation.md.)
Requests (e urllib3, que Requests usa internamente) nunca foram feitos para permitir que você faça algo assim. Portanto, Requests-Racer é forçado a recorrer a alguns hacks bastante terríveis para obter controle fino sobre como as requisições são enviadas.
Esses hacks incluem mexer no estado privado de alguns objetos urllib3, então uma atualização do urllib3 que seja retrocompatível em relação à sua API pública ainda pode quebrar o Requests-Racer. Portanto, recomendo usar Requests-Racer em um virtualenv e instalá-lo antes de Requests ou urllib3, para que uma versão conhecida como compatível dessas bibliotecas seja trazida como dependência.
Para usar Requests-Racer, você precisará de Python 3.5 ou posterior. Primeiro, crie e ative um ambiente virtual Python:
python3 -m venv env
source env/bin/activate
Em seguida, baixe uma cópia da biblioteca e instale-a:
git clone https://github.com/nccgroup/requests-racer.git
cd requests-racer
python setup.py install
Requests-Racer funciona fornecendo um Adaptador de Transporte alternativo para Requests chamado SynchronizedAdapter. Ele coletará todas as requisições que você fizer por meio dele e só as finalizará quando o método finish_all() for chamado:
import requests
from requests_racer import SynchronizedAdapter
s = requests.Session()
sync = SynchronizedAdapter()
s.mount('http://', sync)
s.mount('https://', sync)
resp1 = s.get('http://example.com/a', params={'hello': 'world'})
resp2 = s.post('https://example.net/b', data={'one': 'two'})
# at this point, the requests have been started but not finished.
# resp1 and resp2 should *not* be used.
sync.finish_all()
print(resp1.status_code)
print(resp2.text)
Para simplificar seu código, você também pode usar SynchronizedSession, que é apenas um objeto requests.Session que monta automaticamente um SynchronizedAdapter para HTTP[S] e faz proxy do método finish_all(), então o código acima pode ser reescrito da seguinte forma:
from requests_racer import SynchronizedSession
s = SynchronizedSession()
resp1 = s.get('http://example.com/a', params={'hello': 'world'})
resp2 = s.post('https://example.net/b', data={'one': 'two'})
# at this point, the requests have been started but not finished.
# resp1 and resp2 should *not* be used.
s.finish_all()
print(resp1.status_code)
print(resp2.text)
Aqui estão alguns alertas a ter em mente e coisas mais avançadas que você pode fazer:
SynchronizedAdapter não é thread-safe.SynchronizedAdapter não atualizarão o objeto da sessão (por exemplo, cookies de cabeçalhos Set-Cookie não serão adicionados ao cookie jar da sessão).999 e conterá um traceback no atributo .text.SynchronizedSession.from_regular_session constrói um SynchronizedSession a partir de uma instância de requests.Session. Isso é útil se você precisar fazer algumas requisições simples para, por exemplo, fazer login em um serviço e obter um cookie de sessão que será necessário para as requisições sincronizadas.SynchronizedAdapter e SynchronizedSession aceitam um parâmetro opcional chamado num_threads, que define o número máximo de threads que o adaptador usará. Se não for especificado, o adaptador usará uma thread por requisição.finish_all() aceita um parâmetro opcional chamado timeout, que define o tempo máximo (em segundos) que o adaptador esperará uma thread terminar.Consulte benchmark/ para notas sobre desempenho.
Copyright (C) 2019 Aleksejs Popovs, NCC Group
Este programa é software livre: você pode redistribuí-lo e/ou modificá-lo sob os termos da GNU General Public License conforme publicada pela Free Software Foundation, seja a versão 3 da Licença, ou (a seu critério) qualquer versão posterior.
Este programa é distribuído na esperança de que seja útil, mas SEM QUALQUER GARANTIA; sem mesmo a garantia implícita de COMERCIABILIDADE ou ADEQUAÇÃO A UM DETERMINADO FIM. Veja a GNU General Public License para mais detalhes.
Você deve ter recebido uma cópia da GNU General Public License junto com este programa. Se não, veja https://www.gnu.org/licenses/.