Skip to content

Commit 063c460

Browse files
committed
Support for ENCRYPTION_NON_LOCAL mode
1 parent cbc70f4 commit 063c460

File tree

8 files changed

+83
-25
lines changed

8 files changed

+83
-25
lines changed

src/v1/driver.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,11 @@ let USER_AGENT = "neo4j-javascript/" + VERSION;
174174
* options are as follows:
175175
*
176176
* {
177-
* // Enable TLS encryption. This is on by default in modern NodeJS installs,
177+
* // Encryption level: one of ENCRYPTION_ON, ENCRYPTION_OFF or ENCRYPTION_NON_LOCAL.
178+
* // ENCRYPTION_NON_LOCAL is on by default in modern NodeJS installs,
178179
* // but off by default in the Web Bundle and old (<=1.0.0) NodeJS installs
179180
* // due to technical limitations on those platforms.
180-
* encrypted: true|false,
181+
* encrypted: ENCRYPTION_ON|ENCRYPTION_OFF|ENCRYPTION_NON_LOCAL
181182
*
182183
* // Trust strategy to use if encryption is enabled. There is no mode to disable
183184
* // trust other than disabling encryption altogether. The reason for

src/v1/internal/ch-node.js

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import fs from 'fs';
2323
import path from 'path';
2424
import {EOL} from 'os';
2525
import {NodeBuffer} from './buf';
26+
import {isLocalHost, ENCRYPTION_NON_LOCAL, ENCRYPTION_ON, ENCRYPTION_OFF} from './util';
2627
import {newError} from './../error';
2728

2829
let _CONNECTION_IDGEN = 0;
@@ -71,7 +72,7 @@ const TrustStrategy = {
7172
"to verify trust for encrypted connections, but have not configured any " +
7273
"trustedCertificates. You must specify the path to at least one trusted " +
7374
"X.509 certificate for this to work. Two other alternatives is to use " +
74-
"TRUST_ON_FIRST_USE or to disable encryption by setting encrypted=false " +
75+
"TRUST_ON_FIRST_USE or to disable encryption by setting encrypted=\"" + ENCRYPTION_OFF + "\"" +
7576
"in your driver configuration."));
7677
return;
7778
}
@@ -89,7 +90,8 @@ const TrustStrategy = {
8990
" the signing certificate, or the server certificate, to the list of certificates trusted by this driver" +
9091
" using `neo4j.v1.driver(.., { trustedCertificates:['path/to/certificate.crt']}). This " +
9192
" is a security measure to protect against man-in-the-middle attacks. If you are just trying " +
92-
" Neo4j out and are not concerned about encryption, simply disable it using `encrypted=false` in the driver" +
93+
" Neo4j out and are not concerned about encryption, simply disable it using `encrypted=\"" + ENCRYPTION_OFF +
94+
"\"` in the driver" +
9395
" options."));
9496
} else {
9597
onSuccess();
@@ -115,7 +117,7 @@ const TrustStrategy = {
115117
onFailure(newError("You are using a version of NodeJS that does not " +
116118
"support trust-on-first use encryption. You can either upgrade NodeJS to " +
117119
"a newer version, use `trust:TRUST_SIGNED_CERTIFICATES` in your driver " +
118-
"config instead, or disable encryption using `encrypted:false`."));
120+
"config instead, or disable encryption using `encrypted:\"" + ENCRYPTION_OFF+ "\"`."));
119121
return;
120122
}
121123

@@ -140,7 +142,7 @@ const TrustStrategy = {
140142
"update the file with the new certificate. You can configure which file the driver " +
141143
"should use to store this information by setting `knownHosts` to another path in " +
142144
"your driver configuration - and you can disable encryption there as well using " +
143-
"`encrypted:false`."))
145+
"`encrypted:\"" + ENCRYPTION_OFF + "\"`."))
144146
}
145147
});
146148
});
@@ -150,7 +152,9 @@ const TrustStrategy = {
150152
};
151153

152154
function connect( opts, onSuccess, onFailure=(()=>null) ) {
153-
if( opts.encrypted === false ) {
155+
//still allow boolean for backwards compatibility
156+
if (opts.encrypted === false || opts.encrypted === ENCRYPTION_OFF ||
157+
(opts.encrypted === ENCRYPTION_NON_LOCAL && isLocalHost(opts.host))) {
154158
var conn = net.connect(opts.port, opts.host, onSuccess);
155159
conn.on('error', onFailure);
156160
return conn;
@@ -160,7 +164,7 @@ function connect( opts, onSuccess, onFailure=(()=>null) ) {
160164
onFailure(newError("Unknown trust strategy: " + opts.trust + ". Please use either " +
161165
"trust:'TRUST_SIGNED_CERTIFICATES' or trust:'TRUST_ON_FIRST_USE' in your driver " +
162166
"configuration. Alternatively, you can disable encryption by setting " +
163-
"`encrypted:false`. There is no mechanism to use encryption without trust verification, " +
167+
"`encrypted:\"" + ENCRYPTION_OFF + "\"`. There is no mechanism to use encryption without trust verification, " +
164168
"because this incurs the overhead of encryption without improving security. If " +
165169
"the driver does not verify that the peer it is connected to is really Neo4j, it " +
166170
"is very easy for an attacker to bypass the encryption by pretending to be Neo4j."));

src/v1/internal/ch-websocket.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import {debug} from "./log";
2121
import {HeapBuffer} from "./buf";
2222
import {newError} from './../error';
23+
import {isLocalHost, ENCRYPTION_NON_LOCAL, ENCRYPTION_ON, ENCRYPTION_OFF} from './util';
2324

2425
/**
2526
* Create a new WebSocketChannel to be used in web browsers.
@@ -41,14 +42,16 @@ class WebSocketChannel {
4142
this._handleConnectionError = this._handleConnectionError.bind(this);
4243

4344
let scheme = "ws";
44-
if( opts.encrypted ) {
45+
//Allow boolean for backwards compatibility
46+
if( opts.encrypted === true || opts.encrypted === ENCRYPTION_ON ||
47+
(opts.encrypted === ENCRYPTION_NON_LOCAL && !isLocalHost(opts.host))) {
4548
if( (!opts.trust) || opts.trust === "TRUST_SIGNED_CERTIFICATES" ) {
4649
scheme = "wss";
4750
} else {
4851
this._error = newError("The browser version of this driver only supports one trust " +
4952
"strategy, 'TRUST_SIGNED_CERTIFICATES'. "+opts.trust+" is not supported. Please " +
5053
"either use TRUST_SIGNED_CERTIFICATES or disable encryption by setting " +
51-
"`encrypted:false` in the driver configuration.");
54+
"`encrypted:\"" + ENCRYPTION_OFF + "\"` in the driver configuration.");
5255
return;
5356
}
5457
}

src/v1/internal/connector.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {alloc, CombinedBuffer} from "./buf";
2626
import GraphType from '../graph-types';
2727
import {int, isInt} from '../integer';
2828
import {newError} from './../error';
29+
import {ENCRYPTION_NON_LOCAL, ENCRYPTION_ON, ENCRYPTION_OFF} from './util';
2930

3031
let Channel;
3132
if( WebSocketChannel.available ) {
@@ -423,7 +424,7 @@ function connect( url, config = {}) {
423424
host: host(url),
424425
port: port(url) || 7687,
425426
// Default to using encryption if trust-on-first-use is available
426-
encrypted : (config.encrypted == null) ? hasFeature("trust_on_first_use") : config.encrypted,
427+
encrypted : (config.encrypted == null) || (hasFeature("trust_on_first_use") ? ENCRYPTION_NON_LOCAL : ENCRYPTION_OFF),
427428
// Default to using trust-on-first-use if it is available
428429
trust : config.trust || (hasFeature("trust_on_first_use") ? "TRUST_ON_FIRST_USE" : "TRUST_SIGNED_CERTIFICATES"),
429430
trustedCertificates : config.trustedCertificates || [],

src/v1/internal/util.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
2+
/**
3+
* Copyright (c) 2002-2016 "Neo Technology,"
4+
* Network Engine for Objects in Lund AB [http://neotechnology.com]
5+
*
6+
* This file is part of Neo4j.
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this file except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
21+
let LOCALHOST_MATCHER = /^(localhost|127(\.\d+){3})$/i;
22+
let ENCRYPTION_ON = "ENCRYPTION_ON";
23+
let ENCRYPTION_OFF = "ENCRYPTION_OFF";
24+
let ENCRYPTION_NON_LOCAL = "ENCRYPTION_NON_LOCAL";
25+
26+
function isLocalHost(host) {
27+
return LOCALHOST_MATCHER.test(host);
28+
}
29+
30+
export {
31+
isLocalHost,
32+
ENCRYPTION_ON,
33+
ENCRYPTION_OFF,
34+
ENCRYPTION_NON_LOCAL
35+
}

test/internal/tls.test.js

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ var NodeChannel = require('../../lib/v1/internal/ch-node.js');
2020
var neo4j = require("../../lib/v1");
2121
var fs = require("fs");
2222
var hasFeature = require("../../lib/v1/internal/features");
23+
var isLocalHost = require("../../lib/v1/internal/util").isLocalHost;
2324

2425
describe('trust-signed-certificates', function() {
2526

@@ -34,7 +35,7 @@ describe('trust-signed-certificates', function() {
3435

3536
// Given
3637
driver = neo4j.driver("bolt://localhost", neo4j.auth.basic("neo4j", "neo4j"), {
37-
encrypted: true,
38+
encrypted: "ENCRYPTION_ON",
3839
trust: "TRUST_SIGNED_CERTIFICATES",
3940
trustedCertificates: ["test/resources/random.certificate"]
4041
});
@@ -55,7 +56,7 @@ describe('trust-signed-certificates', function() {
5556

5657
// Given
5758
driver = neo4j.driver("bolt://localhost", neo4j.auth.basic("neo4j", "neo4j"), {
58-
encrypted: true,
59+
encrypted: "ENCRYPTION_ON",
5960
trust: "TRUST_SIGNED_CERTIFICATES",
6061
trustedCertificates: ["build/neo4j/certificates/neo4j.cert"]
6162
});
@@ -90,7 +91,7 @@ describe('trust-on-first-use', function() {
9091
}
9192

9293
driver = neo4j.driver("bolt://localhost", neo4j.auth.basic("neo4j", "neo4j"), {
93-
encrypted: true,
94+
encrypted: "ENCRYPTION_ON",
9495
trust: "TRUST_ON_FIRST_USE",
9596
knownHosts: knownHostsPath
9697
});
@@ -115,7 +116,7 @@ describe('trust-on-first-use', function() {
115116
var knownHostsPath = "test/resources/random_known_hosts";
116117

117118
driver = neo4j.driver("bolt://localhost", neo4j.auth.basic("neo4j", "neo4j"), {
118-
encrypted: true,
119+
encrypted: "ENCRYPTION_ON",
119120
trust: "TRUST_ON_FIRST_USE",
120121
knownHosts: knownHostsPath
121122
});
@@ -128,6 +129,19 @@ describe('trust-on-first-use', function() {
128129
});
129130
});
130131

132+
it('should detect localhost', function() {
133+
expect(isLocalHost('localhost')).toBe(true);
134+
expect(isLocalHost('LOCALHOST')).toBe(true);
135+
expect(isLocalHost('localHost')).toBe(true);
136+
expect(isLocalHost('127.0.0.1')).toBe(true);
137+
expect(isLocalHost('127.0.0.11')).toBe(true);
138+
expect(isLocalHost('127.1.0.0')).toBe(true);
139+
140+
expect(isLocalHost('172.1.0.0')).toBe(false);
141+
expect(isLocalHost('127.0.0.0.0')).toBe(false);
142+
expect(isLocalHost("google.com")).toBe(false);
143+
});
144+
131145
afterEach(function(){
132146
if( driver ) {
133147
driver.close();

test/v1/examples.test.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -344,8 +344,8 @@ describe('examples', function() {
344344
var neo4j = neo4jv1;
345345
// tag::tls-require-encryption[]
346346
var driver = neo4j.driver("bolt://localhost", neo4j.auth.basic("neo4j", "neo4j"), {
347-
// In NodeJS, encryption is on by default. In the web bundle, it is off.
348-
encrypted:true
347+
//In NodeJS, encryption is ENCRYPTION_NON_LOCAL on by default. In the web bundle, it is ENCRYPTION_OFF.
348+
encrypted:"ENCRYPTION_ON"
349349
});
350350
// end::tls-require-encryption[]
351351
driver.close();
@@ -359,7 +359,7 @@ describe('examples', function() {
359359
// in NodeJS, trust-on-first-use is the default trust mode. In the browser
360360
// it is TRUST_SIGNED_CERTIFICATES.
361361
trust: "TRUST_ON_FIRST_USE",
362-
encrypted:true
362+
encrypted:"ENCRYPTION_NON_LOCAL"
363363
});
364364
// end::tls-trust-on-first-use[]
365365
driver.close();
@@ -374,7 +374,7 @@ describe('examples', function() {
374374
// in NodeJS. In the browser bundle the browsers list of trusted
375375
// certificates is used, due to technical limitations in some browsers.
376376
trustedCertificates : ["path/to/ca.crt"],
377-
encrypted:true
377+
encrypted:"ENCRYPTION_NON_LOCAL"
378378
});
379379
// end::tls-signed[]
380380
driver.close();
@@ -385,7 +385,7 @@ describe('examples', function() {
385385
// tag::connect-with-auth-disabled[]
386386
var driver = neo4j.driver("bolt://localhost", {
387387
// In NodeJS, encryption is on by default. In the web bundle, it is off.
388-
encrypted:true
388+
encrypted:"ENCRYPTION_NON_LOCAL"
389389
});
390390
// end::connect-with-auth-disabled[]
391391
driver.close();

test/v1/tck/steps/tlssteps.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ module.exports = function () {
7474
"If you trust that this certificate is valid, simply remove the line starting with localhost:7687 in `known_hosts1`, " +
7575
"and the driver will update the file with the new certificate. You can configure which file the driver should use " +
7676
"to store this information by setting `knownHosts` to another path in your driver configuration - " +
77-
"and you can disable encryption there as well using `encrypted:false`.";
77+
"and you can disable encryption there as well using `encrypted:\"ENCRYPTION_OFF\"`.";
7878
if (this.error.message !== expected) {
7979
callback(new Error("Given and expected results does not match: " + this.error.message + " Expected " + expected));
8080
} else {
@@ -107,7 +107,7 @@ module.exports = function () {
107107

108108
this.Given(/^a driver configured to use a trusted certificate$/, function (callback) {
109109
this.config = {
110-
encrypted: true,
110+
encrypted: "ENCRYPTION_ON",
111111
trust: "TRUST_SIGNED_CERTIFICATES",
112112
knownHosts: this.knownHosts1,
113113
trustedCertificates: ['./test/resources/root.cert']
@@ -132,7 +132,7 @@ module.exports = function () {
132132
//will have to hack a little bit here since the root cert cannot be used by the server since its
133133
//common name is not set to localhost
134134
this.config = {
135-
encrypted: true,
135+
encrypted: "ENCRYPTION_ON",
136136
trust: "TRUST_SIGNED_CERTIFICATES",
137137
knownHosts: this.knownHosts1,
138138
trustedCertificates: [util.neo4jCert]
@@ -156,7 +156,7 @@ module.exports = function () {
156156
"certificate, or the server certificate, to the list of certificates trusted by this driver using " +
157157
"`neo4j.v1.driver(.., { trustedCertificates:['path/to/certificate.crt']}). This is a security measure to protect " +
158158
"against man-in-the-middle attacks. If you are just trying Neo4j out and are not concerned about encryption, " +
159-
"simply disable it using `encrypted=false` in the driver options.";
159+
"simply disable it using `encrypted=\"ENCRYPTION_OFF\"` in the driver options.";
160160
if (this.error.message !== expected) {
161161
callback(new Error("Given and expected results does not match: " + this.error.message + " Expected " + expected));
162162
} else {
@@ -168,7 +168,7 @@ module.exports = function () {
168168
return neo4j.driver("bolt://localhost", neo4j.auth.basic("neo4j", "neo4j"), {
169169
trust: "TRUST_ON_FIRST_USE",
170170
knownHosts: hostFile,
171-
encrypted: true
171+
encrypted: "ENCRYPTION_ON"
172172
});
173173
}
174174
};

0 commit comments

Comments
 (0)