Raketenhandbuchvorleser: Wichtiger Sicherheitshinweis für Abschreiber

Beitrag lesen

Das gezeigte Skript vermeidet zwar (viele) Angriffe auf den lokalen Rechner (DDoS wäre noch möglich...) aber

Wenn Du das Skript verwendest, dann solltest Du

  1. Einen serverseitigen Cache vorsehen, um ggf. Missbrauch(DDoS zu vermeiden.
  2. Verhindern, dass ungültige URLs (Protokolle. Hostnamen) eingegeben werden.
  3. URL-Parameter (alles hinter dem ersten Fragezeichen) sollten blockiert werden. Ansonsten könnte das böse Jungs auf die Idee bringen, den Dienst für Angriffe auf Dritte zu missbrauchen und also die Herkunft des Angriffs zu verschleiern.
  • Ich würde URL-Parameter also nur angemeldeten und mir bekannten Benutzern erlauben.
<?php

define ( 'ALLOW_PARAMS', false );
define (
	'options',
[
	'content_type',
	'http_code',
	'http_connect',
	'http_version',
	'num_connects',
	'num_redirects',
	'redirect_url',
	'remote_ip',
	'remote_port',
	'scheme',
	'size_download',
	'size_header',
	'size_request',
	'speed_download',
	'time_appconnect',
	'time_connect',
	'time_namelookup',
	'time_pretransfer',
	'time_redirect',
	'time_starttransfer',
	'time_total',
	'url_effective'
]
);

# Für Tests in der Konsole:
if ( ! isset( $_GET['URL'] ) ) {
	$_GET['URL'] = 'https://www.example.com/';
  #$_GET['URL'] = 'https://www.%example.com/';
  #$_GET['URL'] = 'https://www.example.com/?foo=bar';
} 

@list( $REST, $DELETED ) = explode('#', trim( $_GET['URL'], 2 ) );
@list( $REST, $GET_PARAMS ) = explode('?', trim( $REST, 2 ) );
$REST = strtolower( $REST );
@list( $PROTO, $REST ) = explode( '://', $REST, 2 );
@list( $HOST, $RESSOURCE ) = explode( '/', $REST, 2 );
$t = preg_replace( '/[^\p{L}\p{N}\._-]/', '', $HOST );
if ( $t != $HOST )  {
	http_response_code ( 403 );
	echo '<h1>Nice Try</h1><hr>';
	trigger_error('Nicht erlaubtes Zeichen in URL: "' . $_GET['URL'] . '"', E_USER_ERROR );
}

if (
	'http' != $PROTO 
and 'https' != $PROTO
) {
	http_response_code ( 404 );
	echo '<h1>Falsches Protokoll</h1><hr><p>Gehen Sie zurück und geben Sie "http://" oder "https://" als Protokoll an.</p>';
	exit;
}

if ( 
	! ALLOW_PARAMS
and $GET_PARAMS 
) {
	http_response_code ( 403 );
	echo '<h1>Verboten: URL enthält Parameter</h1><hr><p>Bitte gehen Sie zurück und geben Sie eine URL ohne Parameter an.</p>';
	exit;		
}

if ( false == dns_get_record( $HOST ) ) {
	http_response_code ( 404 );
	echo '<h1>Hostname unbekannt</h1><hr><p>Für den Hostname konnte kein DNS-Rekord ermittelt werden.</p>';
	exit;	
}

$_GET['URL'] = $PROTO . '://' . $HOST . '/' . $RESSOURCE;	

if (
	ALLOW_PARAMS 
and isset( $GET_PARAMS )
and $GET_PARAMS
) {
	$_GET['URL'] = $_GET['URL'] . '?' . $GET_PARAMS;
} 

$curl_options = [];
$grepHelper = '___THIS_IS_ONLY_FOR_GREP___';

foreach ( options as $s ) {
	$curl_options[] = $grepHelper . $s . ':%{' . $s. '}';
}
$curl_options = implode('\n', $curl_options );
         
$sys = 'LANG=C curl -s -I --write-out "'
       . $curl_options . '" '
       . escapeshellarg( $_GET['URL'] ) 
       . ' 2> /dev/null | grep "^' . $grepHelper . '";'
     ;
$ret = `$sys`;
$ar = explode( "\n", $ret );
$erg = [];
foreach ( $ar as $row ) {
	$row = trim( str_replace( $grepHelper, '', $row ) );
	if ( $row ) {
		list( $name, $value ) = explode( ':', $row, 2);
		$erg[$name] = $value;
	}
}

print_r( $erg );