I was somewhat familiar with Firefox source code a while ago. I was intrigued when they introduced their "Private Browsing" feature. I couldn't find a reason why anybody would need it. ;)
Anyways today I was thinking about what the important aspects of private browsing are and how Firefox's developers would have implemented it - still remembering somewhat how firefox developers maintain network connections.
If a web-server is using HTTP connection's keep-alive setting, expected behavior for Firefox is to honor it. However, the question is when Firefox switches to "Private Browsing" mode, what would Firefox do to these kept-open HTTP connections that already knows who you are? Unfortunately, Firefox keeps them alive. So if you go to these web-sites again after starting the "Private Browsing" mode, they might actually detect you. :(
Here is a sample web-server code that will remember you when you switch to "Private Browsing" mode in Firefox while visiting them. Namely a user:
- Visits the site that is running the code in one of your firefox tabs (let's call this site: Site-A)
- Switches to "Private Browsing" mode
- Enters the URL of the Site-A again and then notices that the Site-A still knows who the user is
Below sample web-server code uses the network socket information to remember who you are in the scenario above. After above step "1" the below code randomly assigns a name to you. Then at above step "3" it remembers your name and tells you who you are.
#!/usr/bin/python
from BaseHTTPServer import BaseHTTPRequestHandler
import threading, socket, SocketServer
import os, random, string, signal
# Ctrl-C
signal.signal(signal.SIGINT, signal.SIG_DFL)
def drop_privileges():
if os.getuid() == 0:
pw = pwd.getpwnam("nobody")
nobody_uid = pw.pw_uid
nobody_gid = pw.pw_gid
os.setgid(nobody_gid)
os.setuid(nobody_uid)
class ThreadedHTTPServer(SocketServer.ThreadingTCPServer):
allow_reuse_address = 1
def server_bind(self):
SocketServer.ThreadingTCPServer.server_bind(self)
host, port = self.socket.getsockname()[:2]
self.server_name = socket.getfqdn(host)
self.server_port = port
class ThreadedHTTPHandler(BaseHTTPRequestHandler):
def log_message(self, format, *args):
print "Session: " + self.session_id + ": Requested: " + str(self.path)
def do_GET(self):
self.session_id = "".join(random.choice(string.ascii_uppercase) for i in range(2))
self.session_id = self.session_id + "-"
self.session_id = self.session_id + "".join(random.choice(string.digits) for i in range(4))
msg_data = "Your name is: " + self.session_id
try:
while True:
msg_type = "text/html"
msg_size = len(msg_data)
self.send_response(200)
self.send_header('Content-type', msg_type)
self.send_header('Content-Length', msg_size)
self.send_header('Connection', 'Keep-Alive')
self.end_headers()
self.wfile.write(msg_data)
# Wait for new request
new_request = []
while True:
msg = self.rfile.readline()
if not msg:
raise IOError()
msg = msg.strip()
if msg is "":
break
new_request.append(msg)
self.path = new_request[0].split(" ")[1]
except IOError:
self.send_error(500,'Server Error')
if __name__ == '__main__':
try:
print 'Start HTTPServer: waiting for requests on port 8080'
server = ThreadedHTTPServer(('', 8080), ThreadedHTTPHandler)
drop_privileges()
server.serve_forever()
except KeyboardInterrupt:
print 'Stop HTTPServer'
server.socket.close()
Please note that the platform that I tested this is Mac running OSX 10.6.7 (i386) and running Mozilla Firefox 3.6.16.
Recent Comments