Electron + MySQL throws security warning - mysql

I've installed Electron and MySql and got them working well together.
https://www.npmjs.com/package/mysql
https://www.electronjs.org/
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>Hello world</h1>
</body>
<script>
var mysql = require('mysql');
var connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'blog'
});
connection.connect();
connection.query('SELECT * FROM posts', function (error, results, fields) {
if (error) throw error;
console.log(results);
});
connection.end();
</script>
</html>
Then in the window I get a security error.
index.html:16 Uncaught ReferenceError: require is not defined
I noticed that I could override it like below.
win = new BrowserWindow({
webPreferences: {
nodeIntegration: true
}
});
I've read it's dangerous and not recommended? I also get a warning when doing so.
Electron Security Warning (Insecure Content-Security-Policy) This renderer process has either no Content Security
Policy set or a policy with "unsafe-eval" enabled. This exposes users of
this app to unnecessary security risks.
How can I get around it?

What you're experiencing here is Electron's out-of-the-box sandboxing. This prevents your renderer process, where your user interface HTML and JavaScript are executed, from being able to access NodeJS APIs so no malicious code can actually do harm to the user's computer. As you said, you can disable this automatic sandboxing by setting nodeIntegration: true, which yields this security warning, but this is not considered a good practice by the Electron developers.
However, if you cannot use some of the workarounds (e.g. by using a preload script; refer to the Electron documentation, specifically this tutorial on context isolation), to get rid of the warning (which really does not do any harm because it won't be displayed when the app is packaged), you may set an environment variable in your main process like so (preferably on the very first line):
process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = true;
// Other main process code...
Although this will remove the warning, I'd leave it where it is so that it can remind you of your security duties and to maybe revisit your code once the app has reached a production-ready state to make it comply with Electron's security guidelines.

Use a preload script instead, and put your MySQL connection code in there. Preload scripts have access to require / the node integration and also have access to the content window at the same time. You can make the preload script add to the global window object to expose functions to connect and perform sql queries.

Related

Web Drop-in integration

I am currently implementing Adyen Web Drop-in integration but ran into a problem testing it on staging.
From the Adyen developer console I can see the API request and response for the session endpoint which returns the sessionData payload as expected.
We then pass sessionData into a page which renders the form correctly.
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script src="https://checkoutshopper-live.adyen.com/checkoutshopper/sdk/5.10.0/adyen.js"
integrity="sha384-LoKEanRPljHoEsT5o+grBn8hgVzoPevwGvRd+gOp/2Xgc4Jx2FQkx29092SKDdeY"
crossorigin="anonymous"></script>
<link rel="stylesheet"
href="https://checkoutshopper-live.adyen.com/checkoutshopper/sdk/5.10.0/adyen.css"
integrity="sha384-DB96UxMFf+ytuAxtum6/9TOoG/y+vUDFbqolCb7OcQvBA+qSrGaRrl81nMADo/+9"
crossorigin="anonymous">
</head>
<body>
<div id="dropin-container"></div>
<script type="text/javascript">
(async () => {
let checkout = await AdyenCheckout(${partnerJsonParameters?string});
checkout.create('dropin').mount('#dropin-container');
})();
</script>
</body>
</html>
Upon filling in the form with a test credit card number and clicking Pay I see two requests in the browser network pane, CORS pre-flight which is fine, and then the second request fails with
{"status":403,"errorCode":"010","message":"Not allowed [This error message is only provided on TEST, this error will be a 500 Internal Error on LIVE.]","errorType":"security"}
I have found two articles on this error, https://www.adyen.help/hc/en-us/articles/360014216000-Why-do-I-receive-a-403-or-010-Not-Allowed-error- and https://docs.adyen.com/development-resources/error-codes#010-not-allowed but the roles seem fine.
I have verified that both the session from server side and checkout config are configured with "test" environment.. any pointers on what else I can try?
After a bit of back and forward with Matthew here's the solution.
We have seen this error happening before on the test environment, and
the best way to resolve is to use another API user. Would it be
possible to create a new API user as described here, or use another of
the existing ones? Using the API Key and Client Key from the new user
should resolve the issue.

WebSocket does not connect to a specific host until Chromium is restarted

we are trying to debug an issue with Chromium (happens in Chrome, Edge, Brave), where it sometimes gets to a state where it does not open a WebSocket to a specific host.
We can see in console logs that it is trying to open the socket, but it never opens the connection. It fails with 1006 error. The same happens in new tabs and in new windows. The behaviour disappears after the browser is restarted or when an incognito tab is used.
There are no HTTP upgrade requests on the server and also the connection does not show up as WebSocket in chrome dev tools. We do not have much else to go on. Any suggestions on what we could try to debug the problem?
I tried to test the web socket with the MS Edge (chromium) Version 83.0.478.58 and Google Chrome Version 83.0.4103.116
In my test, both the Chromium browser works well without 1006 error.
Here is the test code:
<!DOCTYPE html>
<meta charset="utf-8" />
<title>WebSocket Test</title>
<script language="javascript" type="text/javascript">
var wsUri = "wss://echo.websocket.org/";
var output;
function init()
{
output = document.getElementById("output");
testWebSocket();
}
function testWebSocket()
{
websocket = new WebSocket(wsUri);
websocket.onopen = function(evt) { onOpen(evt) };
websocket.onclose = function(evt) { onClose(evt) };
websocket.onmessage = function(evt) { onMessage(evt) };
websocket.onerror = function(evt) { onError(evt) };
}
function onOpen(evt)
{
writeToScreen("CONNECTED");
doSend("WebSocket rocks");
}
function onClose(evt)
{
writeToScreen("DISCONNECTED");
}
function onMessage(evt)
{
writeToScreen('<span style="color: blue;">RESPONSE: ' + evt.data+'</span>');
websocket.close();
}
function onError(evt)
{
writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);
}
function doSend(message)
{
writeToScreen("SENT: " + message);
websocket.send(message);
}
function writeToScreen(message)
{
var pre = document.createElement("p");
pre.style.wordWrap = "break-word";
pre.innerHTML = message;
output.appendChild(pre);
}
window.addEventListener("load", init, false);
</script>
<body>
<h2>WebSocket Test</h2>
<div id="output"></div>
</body>
</html>
Reference:
Web socket echo test
Try to check the security settings of the browsers and also confirm that you are trying to connect using a secure connection.
I found that 1006 is a special code that means the connection was closed abnormally (locally) by the browser implementation.
I suggest you can check WebSocket.onerror(evt) to get more details about the error.
Helpful thread link:
getting the reason why WebSockets closed with close code 1006
If there is more information then you can try to provide us that may help to narrow down the issue.
I observed exactly the same symptom (not sure about the error code) in Brave (but not in Chrome) during 2020 ... it was a constant issue... but since then it didn't happen almost at all since JAN 2021... except last week (in APR 2021) it happened again (in Brave).
Did anyone else notice the issue still being present from time to time? Or maybe it's a new bug, similar but more rare...
Exactly the same behaviour, socket doesn't reconnect except in incognito or after browser restart.
We have been facing this exact issue where Websocket's upgrade requests never reach the server even though the network inspect tab shows that the request has been fired. No amount of refreshing or new tabs help until we switch over to Chrome. The issue is intermittent and has become impossible to debug but nonetheless our users keep reporting infinite loading bars due to the un-connected websocket.
I went through capturing network logs using chrome://net-exports and viewing it on the net-export viewer and the only time I could capture the logs for the issue, I noticed the browser only trying an IPv6 address and not the IPv4 address. (when our servers don't even have one)
Would it be prudent to engage Brave or Chromium team in this? Anyone ever found concrete repro steps for this?

Node.js: My HTML requires an image

See, I was training with Node (and TS btw), and tried to do a trivial server with multiple request/response options. But I have a problem I don't know how to solve without using Express (at least for now I don't want to use it).
I have a HTML file which requests an image file. While in the IDE, everything looks like it's going to work, but when the server is running, the image cannot be found. It's kind of obvious why: The HTML makes a request the server doesn't know how to handle. Thing is, I thought the document could refer to other files without the need of talking to the server.
What is an elegant and working solution for my problem?
Thanks in advance.
import * as http from 'http'
import * as fs from 'fs'
fs.readFile('doc/kmCNHkq.jpg', function (err, data) {
let binaryimg = new Buffer(data).toString('base64');
if (err) throw err;
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'image/jpeg'});
res.end(data);
console.log("Delivered the jpeg");
}).listen(8000);
http.createServer(function(req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(binaryimg);
console.log("Delivered base64 string");
}).listen(8124);
console.log("Unless bug, both servers are listening");
});
fs.readFile('doc/index.html', function(err, data) {
http.createServer(function(req,res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(data)
}).listen(80);
console.log("HTML server is running")
})
(main.ts; Targets ES6)
<html>
<head>
</head>
<body>
<img src="doc/kmCNHkq.jpg"/>
</body>
</html>
(index.html)
Observation: I used to leave the HTML file in '../doc/' and resources on '../img/' however it seems that the HTML uses relative paths, so I copied the image into HTML's folder. If the solution also made it so I could leave the resources on their's respective folders it would be much appreciated.
#Edit:
Now I'm using this switch/case request handler. Working as expected, the HTML's request for the image is interpreted as a normal request (which may not end up scaling well, idk, but screw it). Thanks a lot!
import * as http from 'http'
import * as fs from 'fs'
var stream: fs.ReadStream,
folder = __dirname.substr(0, __dirname.length - 3);
http.createServer(function(req,res) {
switch (req.url){
case('/jpeg'):
stream = fs.createReadStream(folder + 'img/kmCNHkq.jpg');
stream.pipe(res);
console.log("Delivering the jpeg");
break;
case('/base64'):
fs.readFile('img/kmCNHkq.jpg', function (err, data) {
let img64 = new Buffer(data).toString('base64');
if (err) throw err;
res.end(img64);
console.log("Delivered base64 string");
})
break;
case('/html'):
stream = fs.createReadStream(folder + 'doc/index.html');
stream.pipe(res);
console.log("Sending the docs");
break;
default:
console.log("Shit happens");
}
}).listen(80)
(main.ts)
<html>
<body>
<img src="jpeg"/>
</body>
</html>
(index.html)
Short answer:
You won't be able to refer to specific resources on the server (such as your image) unless your server knows how to respond to those requests for that content. It looks like you can probably make your example work easily immediately though by changing the image src to just http://localhost:8000 though.
Longer answer:
Using 'doc/kmCNHkq.jpg' as the src for your image tells your browser that when it loads the page, it should go to the server it got the page from, and ask it for the 'doc/kmCNHkq.jpg' resource. If you specify a full URL including the protocol (the http://) then it will be absolute, instead of relative, so you can request from a different server than the one that served the page.
The servers that you've written don't actually look at the path of the file that's requested though (req.url), and actually they just always return the same content. If you connect to http://localhost:80 (the third server you've created above), and do request that jpg you'll still just get given the same HTML data of the page, because it just runs the two lines in your createServer call at the end of your example. You have written a server that always returns the image however above (the first server), just running on a different port, which is why the above solution works.
Just using that existing server is the simplest solution. The far more conventional approach though is to have just a single HTTP server running on a single port (instead of the 3 you have) and to use req.url to decide what data to return.
Traditionally for static content that means mapping a requested path directly onto the layout of the files on disk, so that requesting doc/abc.jpg looks for a doc folder in the server's directory, and returns the data from abc.jpg therein. That's not required necessarily at all though, and your server can interpret those paths however you like, to return content from anywhere.
(Note than none of this is really anything to do with TypeScript, or even much to do with Node.js. This is really just the essentials of how HTTP servers and browsers interact, and it would be almost identical with any other backing technology. I'd take a look more into the general HTTP and browser details if you're looking to get more background on this.)

HTML5+jQuery+phonegap mobile app security

I'm new to this area and I'm developing a HTML5 mobile app that calls a restful webservices api and exchange JSON objects.
I want to authenticate the client once and give a a key/token that can be used afterwards until a pre-defined expiration date. I have 4 questions:
How can I secure the serverside webservices api? any tools whatsoever?
Can I use the local storage to store the key/token?
What are the phonegap security tools I can use for the client side?
How can I use OAUTH in this case?
How can I secure the serverside webservices api? any tools whatsoever?
OAuth may be overkill for your need, verify that you really need to use such a powerful (and complex) standard.
Two examples of PHP server side software that you may use:
Solberg-OAuth
SimpleSAMLphp
Can I use the local storage to store the key/token?
Yes! Be aware that you MUST use the OAuth 2.0 implicit grant flow in order to obtain the token at the client side.
What are the phonegap security tools I can use for the client side?
ChildBrowser is a plugin to open a separate browserwindow for the authentication process.
I've written a javascript library JSO that can do OAuth 2.0 for you. Other libraries exists as well.
https://github.com/andreassolberg/jso
How can I use OAUTH in this case?
Using JSO with Phonegap and ChildBrowser
Using JSO to perform OAuth 2.0 authorization in WebApps running on mobile devices in hybrid environment is an important deployment scenario for JSO.
Here is a detailed instruction on setting up JSO with Phonegap for iOS and configure OAuth 2.0 with Google. You may use it with Facebook or other OAuth providers as well.
Preparations
Install XCode from App Store, and iOS development kit
Install Phonegap 2.0, Cordova 2.0
Setup App
To create a new App
./create /Users/andreas/Sites/cordovatest no.erlang.test "CordovaJSOTest"
Install ChildBrowser
The original ChildBrowser plugin is available here.
https://github.com/purplecabbage/phonegap-plugins/tree/master/iPhone/ChildBrowser
However, it is not compatible with Cordova 2.0. Instead, you may use this fork of ChildBrowser which should be working with Cordova 2.0:
https://github.com/Shereef/ChildBrowserOnCordova200
What you need to do is to copy these files:
https://github.com/Shereef/ChildBrowserOnCordova200/tree/master/ChildBrowserOnCordova200/Plugins
in to your WebApp project area, by using drag and drop into the Plugins folder in XCode.
Now you need to edit the file found in Resources/Cordova.plist found in your WebApp project area.
In this file you need to add one array entry with '*' into ExternalHosts, and two entries into Plugins:
ChildBrowser -> ChildBrowser.js
ChildBrowserCommand -> ChildBrowserCommand
as seen on the screenshot.
(source: erlang.no)
Setting up your WebApp with ChildBrowser
I'd suggest to test and verify that you get ChildBrowser working before moving on to the OAuth stuff.
In your index.html file try this, and verify using the Simulator.
<script type="text/javascript" charset="utf-8" src="cordova-2.0.0.js"></script>
<script type="text/javascript" charset="utf-8" src="ChildBrowser.js"></script>
<script type="text/javascript">
var deviceready = function() {
if(window.plugins.childBrowser == null) {
ChildBrowser.install();
}
window.plugins.childBrowser.showWebPage("http://google.com");
};
document.addEventListener('deviceready', this.deviceready, false);
</script>
Setting up JSO
Download the latest version of JSO:
https://github.com/andreassolberg/jso
The documentation on JSO is available there as well.
The callback URL needs to point somewhere, and one approach would be to put a callback HTML page somewhere, it does not really matter where, although a host you trust. And put a pretty blank page there:
<!doctype html>
<html>
<head>
<title>OAuth Callback endpoint</title>
<meta charset="utf-8" />
</head>
<body>
Processing OAuth response...
</body>
</html>
Now, setup your application index page. Here is a working example:
<script type="text/javascript" charset="utf-8" src="cordova-2.0.0.js"></script>
<script type="text/javascript" charset="utf-8" src="ChildBrowser.js"></script>
<script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
<script type="text/javascript" charset="utf-8" src="jso/jso.js"></script>
<script type="text/javascript">
var deviceready = function() {
var debug = true;
/*
* Setup and install the ChildBrowser plugin to Phongap/Cordova.
*/
if(window.plugins.childBrowser == null) {
ChildBrowser.install();
}
// Use ChildBrowser instead of redirecting the main page.
jso_registerRedirectHandler(window.plugins.childBrowser.showWebPage);
/*
* Register a handler on the childbrowser that detects redirects and
* lets JSO to detect incomming OAuth responses and deal with the content.
*/
window.plugins.childBrowser.onLocationChange = function(url){
url = decodeURIComponent(url);
console.log("Checking location: " + url);
jso_checkfortoken('facebook', url, function() {
console.log("Closing child browser, because a valid response was detected.");
window.plugins.childBrowser.close();
});
};
/*
* Configure the OAuth providers to use.
*/
jso_configure({
"facebook": {
client_id: "myclientid",
redirect_uri: "https://myhost.org/callback.html",
authorization: "https://www.facebook.com/dialog/oauth",
presenttoken: "qs"
}
}, {"debug": debug});
// For debugging purposes you can wipe existing cached tokens...
// jso_wipe();
// jso_dump displays a list of cached tokens using console.log if debugging is enabled.
jso_dump();
// Perform the protected OAuth calls.
$.oajax({
url: "https://graph.facebook.com/me/home",
jso_provider: "facebook",
jso_scopes: ["read_stream"],
jso_allowia: true,
dataType: 'json',
success: function(data) {
console.log("Response (facebook):");
console.log(data);
}
});
};
document.addEventListener('deviceready', this.deviceready, false);
</script>
How can I secure the serverside webservices api? any tools whatsoever?
Depends on which language the web service is written, php has zend framework for creating web services / nusoap etc. So all of the languages do provide info on how to secure the webservice.
Can I use the local storage to store the key/token?
Yes you can use local storage look at the phonegap documentation
What are the phonegap security tools I can use for the client side?
I dont think so there are any but you can search for some plugins or create your own plugin. Depends on what kind of security do you want to implement.
How can I use OAUTH in this case?
Here is a library for OAuth and this seems to be helpful. You can create a phone gap plugin to interact with the library or use a javascript oauth library(its with sample also).

HTML 5 Geo Location Prompt in Chrome

Just starting to get into HTML 5 and an testing out geo location...liking it so far. I am hitting a bit of a speed bump though...when I try to get my geo location, chrome automatically blocks the page from getting my location. This does not happen at other sites such as the site below:
http://html5demos.com/geo
The scripts I'm using:
<script type="text/javascript" JavaScript" SRC="geo.js"></script>
<script type="text/javascript" JavaScript" SRC="Utility.js"></script>
<script type="text/javascript" JavaScript" SRC="jquery.js"></script>
<script type="text/javascript" JavaScript" SRC="modernizr.js"></script>
function get_location() {
if (geo_position_js.init()) {
geo_position_js.getCurrentPosition(show_map, handle_error);
}
}
function show_map(position) {
var latitude = position.coords.latitude;
var longitude = position.coords.longitude;
alert("lat:" + latitude + " long:" + longitude);
}
function handle_error(err) {
alert(err.code);
if (err.code == 1) {
// user said no!
}
}
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(show_map, handle_error);
} else {
error('not supported');
}
I am testing this out from a local directory on my machine, so there isn't really a "domain" like "http://whatever.com/mytestpage.html". Is this why I am not getting prompted? If so, is it possible to force the browswer to request permission to get the user's geo location and is it possible in my scenario?
There's some sort of security restriction in place in Chrome for using geolocation from a file:/// URI, though unfortunately it doesn't seem to record any errors to indicate that. It will work from a local web server. If you have python installed try opening a command prompt in the directory where your test files are and issuing the command:
python -m SimpleHTTPServer
It should start up a web server on port 8000 (might be something else, but it'll tell you in the console what port it's listening on), then browse to http://localhost:8000/mytestpage.html
If you don't have python there are equivalent modules in Ruby, or Visual Web Developer Express comes with a built in local web server.
None of the above helped me.
After a little research I found that as of M50 (April 2016) - Chrome now requires a secure origin (such as HTTPS) for Geolocation.
Deprecated Features on Insecure Origins
The host "localhost" is special b/c its "potentially secure". You may not see errors during development if you are deploying to your development machine.
As already mentioned in the answer by robertc, Chrome blocks certain functionality, like the geo location with local files. An easier alternative to setting up an own web server would be to just start Chrome with the parameter --allow-file-access-from-files. Then you can use the geo location, provided you didn't turn it off in your settings.
The easiest way is to click on the area left to the address bar and change location settings there. It allows to set location options even for file:///
Make sure it's not blocked at your settings
http://www.howtogeek.com/howto/16404/how-to-disable-the-new-geolocation-feature-in-google-chrome/
if you're hosting behind a server, and still facing issues:
try changing localhost to 127.0.0.1 e.g. http://localhost:8080/ to http://127.0.0.1:8080/
The issue I was facing was that I was serving a site using apache tomcat within an eclipse IDE (eclipse luna).
For my sanity check I was using Remy Sharp's demo:
https://github.com/remy/html5demos/blob/eae156ca2e35efbc648c381222fac20d821df494/demos/geo.html
and was getting the error after making minor tweaks to the error function despite hosting the code on the server (was only working on firefox and failing on chrome and safari):
"User denied Geolocation"
I made the following change to get more detailed error message:
function error(msg) {
var s = document.querySelector('#status');
msg = msg.message ? msg.message : msg; //add this line
s.innerHTML = typeof msg == 'string' ? msg : "failed";
s.className = 'fail';
// console.log(arguments);
}
failing on internet explorer behind virtualbox IE10 on http://10.0.2.2:8080 :
"The current location cannot be determined"
For an easy workaround, just copy the HTML file to some cloud share, such as Dropbox, and use the shared link in your browser. Easy.
I too had this problem when i was trying out Gelocation API. I then started IIS express through visual studio and then accessed the page and It worked without any issue in all browsers.
Check Google Chrome setting and permit location access
Change your default location settings.
On your computer, open Chrome.
At the top right, click More Settings.
Under "Privacy and security," click Site settings.
Click Location.
Turn Ask before accessing on or off.
After I changed those settings, Geolocation worked for me.