Google App Engine Node.js TLS 1.2 - node.js

Our application hosted on Google App Engine Node.js (Flexible Environment). We are now under review of security inspection and failing on the issue that Google App Engine supports TLS 1.0 and 1.1 versions.
Is there a way to enforce the use of only TLS 1.2? And also block ciphers that are below 128 bit?

So I also came up against this problem...and found that GCP weren't that helpful. They'll helpfully restrict at a domain level if a support ticket is put forwards....which resolves the security concern...but you'll still get false positives which need explaining at every penetration test (the GAE shared IPs accept other version of TLS for other domains).
For a nice clean solution; use Cloudflare for your DNS. They essentially act as a middleman/web application firewall. Amongst other things (free certificates, WAF, DDOS mitigation, CDN, HTTPS force, HSTS etc etc etc), you're able to set the minimum TLS version as you wish. Mine is now minimum TLS 1.2, supporting TLS 1.3 if the browser accepts it. I've also essentially only got port 80/443 on GAE connected to cloudflare, with no public access at all, as all traffic goes through cloudflare first. Pretty neat - zero ports open to the public and a fully operations website! The pen test guys just scratched their heads and packed up.
Oh...and FYI - it's free for this level of configuration. Happy security testing ;-)

I can confirm that you can make a request to google support and it takes up to 4 weeks to make the change. Not sure why. Hopefully they can speed things up in the future. But alternatively you can handle this logic at the application layer (in middleware) rather than the network layer. See snippet below:
// using NODEJS + TYPESCRIPT
// disable tls 1.0 and 1.1 weak ciphers
this.app.use((req, res, next) => {
// const cipher = ((req.socket) as TLSSocket).getCipher()
const protocol = ((req.socket) as TLSSocket).getProtocol()
// console.log('cipher: ', cipher);
// output eg: { name: 'ECDHE-RSA-AES128-GCM-SHA256', version: 'TLSv1/SSLv3' }
console.log('protocol: ', protocol);
// output eg: TLSv1.2
if (protocol === 'TLSv1.2' || protocol === 'TLSv1.3') {
next();
} else {
res.status(426);
res.send('request requires TLSv1.2 or greater, please upgrade');
}
});

I've not tried this so I can't guarantee it would work, but it seems like you could use a HTTP(S) Load Balancer. The SSL policies are configurable such that it would likely meet the requirements of your security review.

Related

How do I verify the consistency level configured on the Java driver?

We are currently upgrading from 3.x to 4.x. We are using the programaticBuilder for the DriverConfigLoader. Below is the code for same.
DriverConfigLoader driverConfigLoader = DriverConfigLoader.programmaticBuilder()
.withDuration(DefaultDriverOption.HEARTBEAT_INTERVAL, Duration.ofSeconds(60))
.withString(DefaultDriverOption.REQUEST_CONSISTENCY, ConsistencyLevel.LOCAL_QUORUM.name())
.withString(DefaultDriverOption.RETRY_POLICY_CLASS, "DefaultRetryPolicy")
.withString(DefaultDriverOption.RECONNECTION_POLICY_CLASS, "ConstantReconnectionPolicy")
.withDuration(DefaultDriverOption.RECONNECTION_BASE_DELAY, Duration.ofSeconds(5))
.withString(DefaultDriverOption.LOAD_BALANCING_POLICY_CLASS, "DcInferringLoadBalancingPolicy")
.build();
Wanted to check how to verify this correct setting of ConsistencyLevel when the write/read happens. is there a debug log print mechanism available for this purpose.
Your question suggests that you don't trust that the configured consistency level is not being honoured by the driver so you're looking for proof that it does. To me it doesn't make sense. Perhaps you ran into another problem related to request consistency and you should post information about that instead.
In any case, the DriverConfigLoader is provided for convenience but we discourage its use because it means that you are hard-coding configuration within your app which is bad practice. If you need to make a change, you are forced to have to recompile your app again by virtue that the configuration is hardcoded. Only use the programmatic loader if you have a very specific reason.
The recommended method for configuring the driver options is to use an application configuration file (application.conf). The advantages include:
driver options is configured in a central location,
hot-reload support, and
changes do not require recompiling the app.
To set the basic request consistency to LOCAL_QUORUM:
datastax-java-driver {
basic {
request {
consistency = LOCAL_QUORUM
}
}
}
For details, see Configuring the Java driver. Cheers!
For DataStax Java Driver 4.x version you can do something like this:
CqlSession session = CqlSession.builder().withConfigLoader(driverConfigLoader).build();
DriverConfig config = session.getContext().getConfig();
config.getProfiles().forEach(
(name, profile) -> {
System.out.println("Profile: " + name);
profile.entrySet().forEach(System.out::println);
System.out.println();
});
This will print the values for every defined option in every defined profile. It won't print undefined options though.

Generic domain part with fixed subdomain using Caddy and auto SSL?

I'd like to setup a Caddy server where the subdomain is static but the domain part is "wildcard", such as "api.*"
From my understanding of Caddy, the wildcard is possible for one part of the full domain (*.domain.com matches bar.domain.com but not foo.bar.domain.com).
Moreover, this configuration would automatically create a SSL certificates (which Caddy does in general, but I'm not sure here) for any new DNS entry that points to my server with a domain starting with "api.*".
The "*" here would be the domain directly, not any subdomain (it would work for api.domain.com, but not for api.foo.domain.com).
Is this something possible using a simple Caddy command (such as api.* { ... }, which I tried without luck), or does it need a more complex implementation?
Thank you for your help!
I found a working solution with the help of the Caddy Community.
Here's the code :
{
on_demand_tls {
ask https://static.site.com/domain/verify
interval 2m
burst 5
}
}
static.site.com {
...
}
:443 {
tls {
on_demand
}
// Your custom config, for instance:
reverse_proxy * ...
}
The nifty part is the tls { on_demand } part for your generic HTTPS, which will create a certificate automatically. But, this can be abused by anyone that points one of their DNS entry to your server.
So to avoid that, the Caddy community highly recommends you to set a on_demand_tls that will query an endpoint, and allow the SSL certificate to be created only if that endpoint returns true.
NOTE: The ask is a GET request that DO NOT FOLLOW redirects! Anything but a 200 status code will be considered a failure, even a 3xx!
The ask url will have the ?domain appended and will allow you to verify that domain against your logic, such as custom value in the domain like "starting by static.*", and verify that the domain exists in your database (for example).
If your URL already contains some query parameter, don't worry, Caddy is clever enough to add them. (https://static.site.com/domain/verify?some=query will become https://static.site.com/domain/verify?some=query&domain={domain}.
Caddy support https for the ask parameter, and that URL can also be external with no problems at all (no need for localhost or local server configuration).
I met the same problem, and after 1 day's stucking, here is my solution:
Assuming the site name is: site.com, and I want caddy handle these domains for me:
a.dot.site.com
b.dot.site.com
c.dot.site.com
a.eth.site.com
b.eth.site.com
c.eth.site.com
1.make sure you set SSL access available. e.g. via cloudflare:
2.set the A address pointing to your Caddy server's IP.
2.Caddy file should looks like:
# the key is: you have to list all the patterns for your multiple subdomains
*.site.com *.eth.site.com *.dot.site.com {
reverse_proxy 127.0.0.1:4567
log {
output file /var/log/access-wildcard-site.com.log
}
tls {
dns cloudflare <your cloud flare api key>
}
}

How to force TLS 1.2 usage for PhpMailer 5.2

Recently the 3rd party email service provider I was using made a change. They disabled support for TLS 1.0 and TLS 1.1.
I provide support for an ancient system that still uses php 5.3 and phpmailer 5.2.
My tests indicates that TLS 1.2 is enabled.
But, the PHPMailer code cannot connect to the email server after the disabling of TLS 1.0 and 1.1
Also, note that I am not a full time php expert.
Is there a way to make PHPMailer 5.2 use tls 1.2?
Look for constant STREAM_CRYPTO_METHOD_TLS_CLIENT in file class.smtp.php and update that to STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT
Like this:
public function startTLS()
{
if (!$this->sendCommand('STARTTLS', 'STARTTLS', 220)) {
return false;
}
// Begin encrypted connection
if (!stream_socket_enable_crypto(
$this->smtp_conn,
true,
STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT
)) {
return false;
}
return true;
}
You should run phpinfo() in a small php script on your server to make sure TLS 1.2 is available in the first place.
It's not up to PHPMailer, its up to the version of PHP that you're using to run it, so the solution is to update your PHP version. The major changes relating to TLS were largely in PHP 5.6, so upgrading to that would be a good intermediate point if you're really stuck with this legacy version.

ASP.NET Core WebSockets on IIS 7.5

I know the WebSockets are supported only on Windows 8 and higher. But sometimes you just can't upgrade the system in large organization. So I tried implement WebSockets on ASP.NET Core app.
I take NuGet package "AspNetCore.WebSockets.Server" and run as a self-hosted app on Windows 7 and everything works well. But hosting on IIS7.5 on the same machine wont allow me to upgrade HTTP connection to WebSocket. Even if I try to simulate the handshake the IIS simple removes my "Sec-WebSocket-Accept" header.
static async Task Acceptor(HttpContext hc, Func<Task> next)
{
StringValues secWebSocketKey;
if(hc.Request.Headers.TryGetValue("Sec-WebSocket-Key", out secWebSocketKey))
{
hc.Response.StatusCode = 101;
hc.Response.Headers.Clear();
hc.Response.Headers.Add("Upgrade", new StringValues("websocket"));
hc.Response.Headers.Add("Connection", new StringValues("Upgrade"));
// Disappears on client
hc.Response.Headers.Add("Sec-WebSocket-Accept", new StringValues(GetSecWebSocketAccept(secWebSocketKey[0])));
}
await next();
}
I definitely sure IIS7.5 physically can manage WebSockets if they was implemented by developer and that behavior (header removal) looks like a dirty trick from Microsoft
I am afraid you need IIS 8
With the release of Windows Server 2012 and Windows 8, Internet
Information Services (IIS) 8.0 has added support for the WebSocket
Protocol.
https://www.iis.net/learn/get-started/whats-new-in-iis-8/iis-80-websocket-protocol-support
The new http.sys is the one that can turn a regular HTTP connection into a binary communication for websockets. Although you can implement your own thing, you cannot hook it into http.sys.

Resolve mDNS .local URL in browser address bar

I am trying to run a HTTP server in my LAN and want to access it by using a browser on another desktop machine. As I do not like typing the IP address and port manually I tried setting up a mDNS using jmDNS.
String type = "_http._tcp.local.";
jmdns = JmDNS.create();
jmdns.addServiceListener(type, listener = new ServiceListener() {
#Override
public void serviceResolved(ServiceEvent ev) {
Log.d(LogTag.SERVER, "Service resolved: " + ev.getInfo().getQualifiedName() + " port:"
+ ev.getInfo().getPort());
}
#Override
public void serviceRemoved(ServiceEvent ev) {
Log.d(LogTag.SERVER, "Service removed: " + ev.getName());
}
#Override
public void serviceAdded(ServiceEvent event) {
// Required to force serviceResolved to be called again (after the first search)
jmdns.requestServiceInfo(event.getType(), event.getName(), 1);
}
});
serviceInfo = ServiceInfo.create(type, NAME, PORT, "test service");
jmdns.registerService(serviceInfo);
The mDNS entry shows up on ZeroConf Browser app just fine. The server is reachable by IP and port just fine.
On Windows 7 typing the name with the .local TLD (= http://roseblade.local/) into any address bar (Firefox, Chrome, Safari, IE) does not do much and from what my research shows is pretty much a futile task anyway. I installed Apple Bonjour but that only help running Hobbyist Software's Bonjour Browser.
As far as Linux goes I tried the same with elemantaryOS and Midori but that also did not work.
OSX or iOS is currently not available to me.
How can I get the resolution of the .local address to work in my browser (Firefox, Chrome, whatever on Linux, OSX or Windows7)? Am I doing something wrong? At this point I would just like to verify that mDNS can work like that on a system.
Pointers to material on the issue are also appreciated.
mDNS and Bonjour can be a little confusing because they actually encompass a few different functionalities. Service discovery, which I believe is what you have implemented, is one. Resolving an address--which is what you're looking for--is separate, and needs to be solved separately. Once you have address resolution working, you can point your service discovery at the DNS records provided by your resolver.
mDNS address resolution works by multicasting a DNS query over the network. By binding to a UDP port, listening for queries, and answering them, you can provide DNS records to mDNS clients. To do this, you can use an existing mDNS server like avahi-daemon, or, if you need custom functionality or integration with your application, implement one using something like Node.js's multicast-dns.
However, in my experience, this has been rather flakey. Some network configurations interfere with mDNS resolution, as do some OSes (eg. iOS 8, see the whole debate around discoveryd vs. mDNSResponder).

Resources