timing attack identity correlation prevention added, python3 test, more fingerprinting prevention, began work on PGP core

master
Kevin Froman 2018-01-05 03:16:21 -06:00
parent fb0309a414
commit 2898dbaafa
No known key found for this signature in database
GPG Key ID: 0D414D0FE405B63B
6 changed files with 60 additions and 12 deletions

View File

@ -1,3 +1,7 @@
Onionr Logo is licensed under Creative Commons Attribution-Share Alike 3.0 Unported
https://creativecommons.org/licenses/by-sa/4.0/
GNU GENERAL PUBLIC LICENSE GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007 Version 3, 29 June 2007

37
api.py
View File

@ -15,7 +15,7 @@
''' '''
import flask import flask
from flask import request, Response, abort from flask import request, Response, abort
import configparser, sys, random, threading, hmac, hashlib, base64 import configparser, sys, random, threading, hmac, hashlib, base64, time, math, gnupg
from core import Core from core import Core
''' '''
@ -31,6 +31,8 @@ class API:
def __init__(self, config, debug): def __init__(self, config, debug):
self.config = config self.config = config
self.debug = debug self.debug = debug
self._privateDelayTime = 3
self._core = Core()
app = flask.Flask(__name__) app = flask.Flask(__name__)
bindPort = int(self.config['CLIENT']['PORT']) bindPort = int(self.config['CLIENT']['PORT'])
self.bindPort = bindPort self.bindPort = bindPort
@ -44,11 +46,14 @@ class API:
@app.before_request @app.before_request
def beforeReq(): def beforeReq():
self.requestFailed = False
return return
@app.after_request @app.after_request
def afterReq(resp): def afterReq(resp):
if not self.requestFailed:
resp.headers['Access-Control-Allow-Origin'] = '*' resp.headers['Access-Control-Allow-Origin'] = '*'
else:
resp.headers['server'] = 'Onionr' resp.headers['server'] = 'Onionr'
resp.headers['content-type'] = 'text/plain' resp.headers['content-type'] = 'text/plain'
resp.headers["Content-Security-Policy"] = "default-src 'none'" resp.headers["Content-Security-Policy"] = "default-src 'none'"
@ -57,29 +62,47 @@ class API:
@app.route('/client/') @app.route('/client/')
def private_handler(): def private_handler():
startTime = math.floor(time.time())
# we should keep a hash DB of requests (with hmac) to prevent replays # we should keep a hash DB of requests (with hmac) to prevent replays
action = request.args.get('action') action = request.args.get('action')
#if not self.debug: #if not self.debug:
token = request.args.get('token') token = request.args.get('token')
if not self.validateToken(token): if not self.validateToken(token):
abort(403) abort(403)
self.validateHost() self.validateHost('private')
if action == 'hello': if action == 'hello':
resp = Response('Hello, World! ' + request.host) resp = Response('Hello, World! ' + request.host)
elif action == 'stats': elif action == 'stats':
resp = Response('something') resp = Response('something')
elif action == 'init':
# generate PGP key
pass
else: else:
resp = Response('(O_o) Dude what? (invalid command)') resp = Response('(O_o) Dude what? (invalid command)')
endTime = math.floor(time.time())
elapsed = endTime - startTime
if elapsed < self._privateDelayTime:
time.sleep(self._privateDelayTime - elapsed)
return resp return resp
@app.route('/public/')
def public_handler():
# Public means it is publicly network accessible
self.validateHost('public')
action = request.args.get('action')
@app.errorhandler(404) @app.errorhandler(404)
def notfound(err): def notfound(err):
resp = Response("\_(0_0)_/ I got nothin") self.requestFailed = True
resp = Response("")
#resp.headers = getHeaders(resp) #resp.headers = getHeaders(resp)
return resp return resp
@app.errorhandler(403) @app.errorhandler(403)
def authFail(err): def authFail(err):
resp = Response("Auth required/security failure") self.requestFailed = True
resp = Response("403")
return resp return resp
print('Starting client on ' + self.host + ':' + str(bindPort)) print('Starting client on ' + self.host + ':' + str(bindPort))
@ -87,13 +110,17 @@ class API:
app.run(host=self.host, port=bindPort, debug=True, threaded=True) app.run(host=self.host, port=bindPort, debug=True, threaded=True)
def validateHost(self): def validateHost(self, hostType):
if self.debug: if self.debug:
return return
# Validate host header, to protect against DNS rebinding attacks # Validate host header, to protect against DNS rebinding attacks
host = self.host host = self.host
if hostType == 'private':
if not request.host.startswith('127'): if not request.host.startswith('127'):
abort(403) abort(403)
elif hostType == 'public':
if not request.host.endswith('onion') and not request.hosst.endswith('i2p'):
abort(403)
# Validate x-requested-with, to protect against CSRF/metadata leaks # Validate x-requested-with, to protect against CSRF/metadata leaks
''' '''
try: try:

View File

@ -13,13 +13,18 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
''' '''
import sqlite3, os, time, math import sqlite3, os, time, math, gnupg
class Core: class Core:
def __init__(self): def __init__(self):
self.queueDB = 'data/queue.db' self.queueDB = 'data/queue.db'
#self.daemonQueue() # Call to create the DB if it doesn't exist #self.daemonQueue() # Call to create the DB if it doesn't exist
return return
def generateMainPGP(self):
# Generate main pgp key
gpg = gnupg.GPG(gnupghome='data/pgp/')
return
def daemonQueue(self): def daemonQueue(self):
# This function intended to be used by the client # This function intended to be used by the client
# Queue to exchange data between "client" and server. # Queue to exchange data between "client" and server.

View File

@ -43,7 +43,7 @@ class Onionr:
randomPort = 8080 randomPort = 8080
else: else:
randomPort = random.randint(1024, 65535) randomPort = random.randint(1024, 65535)
self.config['CLIENT'] = {'CLIENT HMAC': base64.b64encode(os.urandom(32)).decode('utf-8'), 'PORT': randomPort} self.config['CLIENT'] = {'CLIENT HMAC': base64.b64encode(os.urandom(32)).decode('utf-8'), 'PORT': randomPort, 'API VERSION': '0.0.0'}
with open('data/config.ini', 'w') as configfile: with open('data/config.ini', 'w') as configfile:
self.config.write(configfile) self.config.write(configfile)
command = '' command = ''
@ -67,6 +67,8 @@ class Onionr:
return return
return return
def daemon(self): def daemon(self):
os.system('./communicator.py')
print('Started communicator')
api.API(self.config, self.debug) api.API(self.config, self.debug)
return return
def killDaemon(self): def killDaemon(self):

View File

@ -3,3 +3,7 @@
P2P microblogging platform and social network, using Tor & I2P. P2P microblogging platform and social network, using Tor & I2P.
Major work in progress. *NOT USABLE OR SAFE YET* Major work in progress. *NOT USABLE OR SAFE YET*
# Development

View File

@ -17,6 +17,12 @@
import unittest, sys, os import unittest, sys, os
class OnionrTests(unittest.TestCase): class OnionrTests(unittest.TestCase):
def testPython3(self):
if sys.version_info.major != 3:
print(sys.version_info.major)
self.assertTrue(False)
else:
self.assertTrue(True)
def testNone(self): def testNone(self):
print('--------------------------') print('--------------------------')
print('Running simple program run test') print('Running simple program run test')