2

I see this happening allot: developers need to test stuff, have a self-signed certificate that causes an error, and they just switch verification off globally (like in this example). The hack gets forgotten and then the code goes into production like that...

It can be detected by providing a bad certificate and see if the client accepts it, but is there a standard feature so we can we configure web-servers in a way that they will deliberately do that the first time for every distinct client?

  • Legal questions are off topic here - there are just too many different jurisdictions which could apply. It also raises other issues: whose fault would it be? Developer? Testing engineers? System administrator? Would it matter what the impact of this was? It could be worse for a bank system which results in massive losses, but the same issue could affect a personal site, with no actual impact. – Matthew Jun 21 '18 at 15:34
  • In most countries, companies can be fined for data breaches. Whether they would for this particular flaw in less clear. – paj28 Jun 21 '18 at 15:36
  • 2
    Louis - I have removed the off topic part of your question. – Rory Alsop Jun 21 '18 at 15:53
  • Thanks @RoryAlsop, I was hoping I could put some more weight behind my arguments against this. But practical advice is also valuable. – Louis Somers Jun 22 '18 at 8:09
4

... but is there a standard feature so we can we configure web-servers in a way that they will deliberately do that the first time for every distinct client?

There is no such feature. Since the TLS handshake (which serves the certificate) is done before any kind of application data (like a application specific user-agent header) gets submitted and since there is no kind of application-specific identifier in the TLS handshake too a server cannot figure out of this is a new type of client application or not and thus cannot behave differently.

  • That's a shame, I guess it would be a nice feature on corporate firewall / proxy servers. A monthly test for each unique client IP address to a specific domain should catch many of these. I'm not sure how clients should handle this though, if the fake certificate has a tell-tale flag that it's a test, then that test could be faked by the client. But in the case of such a test it is desired that the client just does a retry with a new connection ignoring the first invalid certificate, only to report failure if the subsequent connection also gives certificate failures. – Louis Somers Jun 27 '18 at 11:34
0

Sadly there is no such feature as it's the TLS handshake failing which is before it should ever hit application logic. However you might be missing the real problem here in all truth and honesty if someone has released code that is not verifying TLS correctly or is actively ignoring TLS errors.

The problem of inexperienced coders not knowing how to test their code

enter image description here

Of course this comic is missing the expert programmer: "Oh it's finally passing all of it's tests. Good."

I think a bigger question is "Why does a developer need a self signed certificate?" and if the answer is "Testing" then there are much better, safer, and easier ways to handle testing that don't require certificates or servers. If a developer cannot figure out how to test code for a server or client application outside of a client and server environment then what is that code doing in the production code base and why is that developer not receiving help to bring them up to faster and safer practices and design patterns?

With code being just that: code; there are infinitely many ways to test it that don't require a server, certificate, or even man hours. They should adopt those ways moving forward, and retroactively integrate those patterns into older code.

"But what if a developer doesn't want to?" is a common argument against this. To that the answer is "Then go find a developer who believes in proper and safe design practices." End. Of. Story. It is not worth the bugs, headaches, and lost time/profit they will introduce with their rampant disregard for standards set in place by those more experienced than themselves they could learn from. It doesn't matter if they've have more years of experience either, because their experience is wrong. It's especially more so since these design practices are free and readily available.

With a load of free resources and proper instruction it's a wonder that anything other than a small inexperienced company would ever run into this situation but it does happen. Even then it's not surprising that many of these companies eventually reach the same point in time where they do adopt these practices.


An example

Now this may seem like I'm just ranting and raving(with would be cathartic) but in all honesty this is an easy pattern to adopt. Lets look at an example for NodeJS route handler

In this example we are going to write a route handler that will log a visitor to the site, and then proceed to the next handler.

handler.js

module.exports = route //export the route for importing and compilation in another file
function route(req, res, next){
  req.app.locals.plugins.logVisit(req)
    .then(error => error ? next(error) : next())
}

Now we need to test this route. Lets write up a test without any testing library that will output the number of succeeded tests and failed tests and only test this route

test.js

let handler = require('./handler')
let passed = 0;
let failed = 0;

let goodReq = {
  app: {
    locals: {
      plugins: {
        logVisit(req){
          req != null
            ? ++passed && console.log('Properly passed the request object for logging')
            : ++failed && console.log('Did not pass the request object for logging')
            return Promise.resolve()
        }
      }
    }
  }
}

let goodNext = function (error){
  if (error){
    return ++failed && console.log('Improperly handled a good logVisit call')
  }
  ++passed && console.log('Properly handled a good logVisit call')
}

let badReq = {
  app:{
    locals:{
      plugins:{
        logVisit(req){
          req != null
            ? ++passed && console.log('Properly passed the request object for logging')
            : ++failed && console.log('Did not pass the request object for logging')
            return Promise.resolve(new Error('Failed logVisit called'))
        }
      }
    }
  }
}

let badNext = function (error){
  if (!error){
    return ++failed && console.log('Failed handling an error logVisit call')
  }
  ++passed && console.log('Properly handled an errored logVisit call')
}

typeof handler == 'function'
  ? ++passed && console.log('The handler is a function')
  : ++failed && console.log('The handler is not a function')
if (failed) {
  throw new Error('The handler is not a function. It cannot be called as such, aborting future tests')
}


console.log('Handler will call logVisit and recieve a non errored state')
handler(goodReq, null, goodNext)
if (failed) {
  throw new Error('The handler did not properly call and handle logVisit success. Aborting future tests')
}

console.log('Handler will call logVisit and recieve an errored state')
handler(badReq, null, badNext)
if (failed) {
  throw new Error('The handler did not properly call and handle logVisit error. Aborting future tests')
}

setTimeout(() => {
  console.log('All tests for the handler passed! It is now ready for integration testing')
  console.log('# of Tests: ', (passed + failed))
  console.log('Number of failed tests: ', failed)
  console.log('Number of passed tests: ', passed)
}, 1000);

As you can see we don't even NEED a server to test the code, or a self signed certificate or even a testing library(although that probably would have made it easier to test). Before this handler would ever go into a server, it would be tested. At that point the developer already knows it works as intended. It doesn't need a self signed certificate. It can also be proven that the tests work by running them.

As long as you have proper testing, you don't need a self signed certificate.

  • I also feel a deep sensation of "anger" when I encounter this, but on the other hand it cannot always be avoided. Unit testing has its place, but cannot replace integration tests. And 90% of the time developing and testing is done against 3rd party test environments which are out of our control. In real life developers often have to "discover" the real API since documentation (if any) is usually outdated. For now we'll have to do with periodic grep searches on "ServerCertificateValidationCallback" in the source as a testing mechanism. An error provided by the webserver would be much better! – Louis Somers Jun 22 '18 at 7:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.