mirror of https://github.com/huashengdun/webssh
Support cross origin connect
parent
b4ca604518
commit
713ae1e8f1
|
@ -449,6 +449,7 @@ class OtherTestBase(AsyncHTTPTestCase):
|
|||
syshostfile = ''
|
||||
tdstream = ''
|
||||
maxconn = 20
|
||||
origin = 'same'
|
||||
body = {
|
||||
'hostname': '127.0.0.1',
|
||||
'port': '',
|
||||
|
@ -467,6 +468,7 @@ class OtherTestBase(AsyncHTTPTestCase):
|
|||
options.syshostfile = self.syshostfile
|
||||
options.tdstream = self.tdstream
|
||||
options.maxconn = self.maxconn
|
||||
options.origin = self.origin
|
||||
app = make_app(make_handlers(loop, options), get_app_settings(options))
|
||||
return app
|
||||
|
||||
|
@ -716,3 +718,28 @@ class TestAppWithTooManyConnections(OtherTestBase):
|
|||
self.assertEqual(data['status'], 'Too many connections.')
|
||||
|
||||
ws.close()
|
||||
|
||||
|
||||
class TestAppWithCrossOriginConnect(OtherTestBase):
|
||||
|
||||
origin = 'http://www.example.com'
|
||||
|
||||
@tornado.testing.gen_test
|
||||
def test_app_with_cross_orgin_connect(self):
|
||||
url = self.get_url('/')
|
||||
client = self.get_http_client()
|
||||
body = urlencode(dict(self.body, username='foo', _origin='localhost'))
|
||||
response = yield client.fetch(url, method='POST', body=body,
|
||||
headers=self.headers)
|
||||
data = json.loads(to_str(response.body))
|
||||
self.assertIsNone(data['id'])
|
||||
self.assertIsNone(data['encoding'])
|
||||
self.assertIn('Cross origin frame', data['status'])
|
||||
|
||||
body = urlencode(dict(self.body, username='foo', _origin=self.origin))
|
||||
response = yield client.fetch(url, method='POST', body=body,
|
||||
headers=self.headers)
|
||||
data = json.loads(to_str(response.body))
|
||||
self.assertIsNotNone(data['id'])
|
||||
self.assertIsNotNone(data['encoding'])
|
||||
self.assertIsNone(data['status'])
|
||||
|
|
|
@ -76,6 +76,28 @@ class MixinHandler(object):
|
|||
else:
|
||||
self.context = context
|
||||
|
||||
def check_origin(self, origin):
|
||||
if self.origin_policy == '*':
|
||||
return True
|
||||
|
||||
parsed_origin = urlparse(origin)
|
||||
netloc = parsed_origin.netloc.lower()
|
||||
logging.debug('netloc: {}'.format(netloc))
|
||||
|
||||
host = self.request.headers.get('Host')
|
||||
logging.debug('host: {}'.format(host))
|
||||
|
||||
if netloc == host:
|
||||
return True
|
||||
|
||||
if self.origin_policy == 'same':
|
||||
return False
|
||||
elif self.origin_policy == 'primary':
|
||||
return is_same_primary_domain(netloc.rsplit(':', 1)[0],
|
||||
host.rsplit(':', 1)[0])
|
||||
else:
|
||||
return origin in self.origin_policy
|
||||
|
||||
def is_forbidden(self, context, hostname):
|
||||
ip = context.address[0]
|
||||
lst = context.trusted_downstream
|
||||
|
@ -340,6 +362,13 @@ class IndexHandler(MixinHandler, tornado.web.RequestHandler):
|
|||
if len(clients.get(self.src_addr[0], {})) >= options.maxconn:
|
||||
raise tornado.web.HTTPError(403, 'Too many connections.')
|
||||
|
||||
origin = self.get_argument('_origin', u'')
|
||||
if origin:
|
||||
if not self.check_origin(origin):
|
||||
raise tornado.web.HTTPError(
|
||||
403, 'Cross origin frame operation is not allowed.'
|
||||
)
|
||||
|
||||
future = Future()
|
||||
t = threading.Thread(target=self.ssh_connect_wrapped, args=(future,))
|
||||
t.setDaemon(True)
|
||||
|
@ -364,28 +393,6 @@ class WsockHandler(MixinHandler, tornado.websocket.WebSocketHandler):
|
|||
super(WsockHandler, self).initialize(loop)
|
||||
self.worker_ref = None
|
||||
|
||||
def check_origin(self, origin):
|
||||
if self.origin_policy == '*':
|
||||
return True
|
||||
|
||||
parsed_origin = urlparse(origin)
|
||||
netloc = parsed_origin.netloc.lower()
|
||||
logging.debug('netloc: {}'.format(netloc))
|
||||
|
||||
host = self.request.headers.get('Host')
|
||||
logging.debug('host: {}'.format(host))
|
||||
|
||||
if netloc == host:
|
||||
return True
|
||||
|
||||
if self.origin_policy == 'same':
|
||||
return False
|
||||
elif self.origin_policy == 'primary':
|
||||
return is_same_primary_domain(netloc.rsplit(':', 1)[0],
|
||||
host.rsplit(':', 1)[0])
|
||||
else:
|
||||
return origin in self.origin_policy
|
||||
|
||||
def open(self):
|
||||
self.src_addr = self.get_client_addr()
|
||||
logging.info('Connected from {}:{}'.format(*self.src_addr))
|
||||
|
|
|
@ -50,6 +50,7 @@ jQuery(function($){
|
|||
messages = {1: 'This client is connecting ...', 2: 'This client is already connnected.'},
|
||||
key_max_size = 16384,
|
||||
fields = ['hostname', 'port', 'username'],
|
||||
event_origin,
|
||||
hostname_tester = /((^\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\s*$)|(^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$))|(^\s*((?=.{1,255}$)(?=.*[A-Za-z].*)[0-9A-Za-z](?:(?:[0-9A-Za-z]|\b-){0,61}[0-9A-Za-z])?(?:\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|\b-){0,61}[0-9A-Za-z])?)*)\s*$)/;
|
||||
|
||||
|
||||
|
@ -517,6 +518,9 @@ jQuery(function($){
|
|||
}
|
||||
|
||||
data._xsrf = _xsrf.value;
|
||||
if (event_origin) {
|
||||
data._origin = event_origin;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: url,
|
||||
|
@ -569,4 +573,31 @@ jQuery(function($){
|
|||
connect();
|
||||
});
|
||||
|
||||
|
||||
function cross_origin_connect(event)
|
||||
{
|
||||
console.log(event.origin);
|
||||
var prop = 'connect',
|
||||
args;
|
||||
|
||||
try {
|
||||
args = JSON.parse(event.data);
|
||||
} catch (SyntaxError) {
|
||||
args = event.data.split('|');
|
||||
}
|
||||
|
||||
if (!Array.isArray(args)) {
|
||||
args = [args];
|
||||
}
|
||||
|
||||
try {
|
||||
event_origin = event.origin;
|
||||
wssh[prop].apply(wssh, args);
|
||||
} finally {
|
||||
event_origin = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('message', cross_origin_connect, false);
|
||||
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue