What's new

Forced HTTPS redirects?

  • SNBForums Code of Conduct

    SNBForums is a community for everyone, no matter what their level of experience.

    Please be tolerant and patient of others, especially newcomers. We are all here to share and learn!

    The rules are simple: Be patient, be nice, be helpful or be gone!

AndreiGuru

Occasional Visitor
Hello,

With the recent KRACK attacks, and lack of client updates for whatever reason, I was wondering if anyone's using a method to force the use of HTTPS. An easy to implement method which comes to mind is redirecting all outbound http traffic through a local "service" via iptables, which would then simply reply back to the client with a 30x redirect to the https endpoint. The reason I mention "service" is because this can be done using a simple Perl script with a few lines of code vs having to install an actual web server.

I'm aware that not all sites have https support, and certain https endpoints will not use the same host as the http variant. However, I feel those inconsistencies can easily be coded around using whitelist and custom https endpoint options. For example, two options come to mind:

- Whitelisting: Giving the user the ability to whitelist http:// requests by client IP/target FQDN
- Custom mapping: For example mapping http://w.sharethis.com to https://ws.sharethis.com
 
Last edited:
On the browser side of things you can look into the plugin HTTPS Everywhere by the EFF
 
Hello,

Thanks for the browser tip, however this is in regards to forcing traffic on the router vs client-based. There are quite a few devices and firmwares which have huge delays in updates, or never update at all. As such, I'm looking to force https for them, vs simply blocking all http traffic.
 
Last edited:
Can't be done router-side, because the browser has to be the one deciding to use TLS. Just redirecting to port 443 will simply result in a failed connection, as the browser will try to connect without TLS.

Closest you might get something like this running would be by using a full-fledged proxy. Not something I'd recommend running on a low-powered router.
 
Can't be done router-side, because the browser has to be the one deciding to use TLS. Just redirecting to port 443 will simply result in a failed connection, as the browser will try to connect without TLS.

Closest you might get something like this running would be by using a full-fledged proxy. Not something I'd recommend running on a low-powered router.

I think my initial post was misread. This can be done router side, and I wasn't planning on merely rerouting 80 to 443. The "proxying"/redirect aspect would be done in the form of a 301/302 redirect, sent by the Perl script listening for requests. All outbound HTTP traffic would be rerouted through the Perl script, which will send back basic HTTP headers to the client to force the browser redirect (picture a .htaccess https redirect, but using MITM on the router) using IO::Socket. For example, this is what would be happening:

- Client1 requests http://google.com/abc
- Router redirects the request via iptables to the local "service"
- Local "service" responds to Client1 with a "Location: https://google.com/abc" + basic HTTP headers, for the "forced" redirect.
- Client1 then does the rest.

There's no worry of the http(s) scheme mismatching or large overhead from using a proxy service.
 
Last edited:
I got a bit sidetracked with dinner and didn't have a chance to do the whitelisting/custom host mapping. However, I did toss together a working PoC, which uses threads to avoid request blocking and only around 8MB of RAM:

Proc:
Code:
admin@RT-AC5300-63B0:/# ps|awk '!/awk/ && /VSZ|tssl/'
  PID USER       VSZ STAT COMMAND
19554 admin     8676 S    perl ./tssl.pl
admin@RT-AC5300-63B0:/#

IPTables:
Code:
iptables -t nat -I PREROUTING -p tcp -m tcp --dport 80 -j DNAT --to-destination 192.168.1.1:9009

Redirect service script:
Code:
#!/usr/bin/env perl

use strict;
use warnings;
use IO::Socket;
use threads;
my $port   = 9009;
my $read_timeout = '10'; # value in seconds


my $server = IO::Socket::INET->new(
    Proto     => 'tcp',
    LocalPort => $port,
    Listen    => SOMAXCONN,
    Reuse     => 1
);
die "Can't start service." unless $server;
$| = 1; # disable buffering

print "[Server $0 accepting clients]\n";

while ( my $connection = $server->accept ) {
    # spawn a new thread per connection (avoid request blocking)
    threads->create( "do_redirect", $connection )->detach;
}

sub do_redirect {
    my $socket = shift;
    setsockopt( $socket, SOL_SOCKET, SO_RCVTIMEO, pack( 'L!L!', +${read_timeout}, 0 ) );
    my $source = $socket->peerhost() . ":" . $socket->peerport();
    my ($uri,$host);
    my $date   = localtime;
    print ">> Connection from $source\n";

    # Read request up to a empty line
    while (<$socket>) {
        last unless /\S/;
        $uri  = $2 if ( $_ =~ /(GET|HEAD|POST) (\S+) (HTTP)/m );
        $host = $2 if ( $_ =~ /(?i)(Host:\s+)(\S+)/m );

    }
    if ( $uri && $host ) {
        my $target = "https://${host}${uri}";
        print ">> Redirecting $source to: $target\n";
        print $socket "HTTP/1.1 302 Found\nDate: ${date}\nLocation: ${target}\nConnection: close\nContent-Length: 0\r\n\r\n";
    }
    else {
        print ">> Invalid request from $source";
    }
    close $socket;
    print ">> $source client closed\n";
}
 

Latest threads

Sign Up For SNBForums Daily Digest

Get an update of what's new every day delivered to your mailbox. Sign up here!
Top