M2M communication via HTTPS - How to authenticate? - php

Requirements
I'm currently working on a PHP portal for a machine-seller. His machines are capable of communicating over the internet with an integrated SBC with LAN port. The consumers who bought a machine can configure it online after they logged in to the machine-sellers-portal.
After they configured it online, they can download the configuration file via the HMI (touch display at the machine itself) to the machine. The configuration file contains valuable and private information.
The HMI is not browser based. It's a binary application that has, for example, a button "Load config". The rest has to be done in bash/php-scripts in the backround.
Solution for authentication?
I'm in a very early state of conception, but I'm wondering about some processes. I've never had a machine thats needs access to my services, only humans. What is the way to do this actually?
I have three approaches:
1. Access with "API-Key"
Means: In the OS of the SBC lies a file containing a sequence like 8asd7d7d. When I receive a GET-request to portal.company.com/getConfig/8asd7d7d I know from which machine it comes and that it is allowed to receive this config.
Disadvantage: The buyer has access to the SBCs file system. He could destroy the file by accident. He could find out the generating scheme and download configuration files from other buyers.
2. Generating one-time UUID-URL
Means: The consumer creates his configuration online. After that, he gets displayed a one-time URL like portal.company.com/getConfig/d8ac2292ea1fec3fe5c65e6ef573 which he can enter in the HMI and load the file.
Disadvantage: The consumer has to type a long URL into the display of the HMI.
3. Simulating the human authentication process
Means: The machine sends a valid post-request to portal.company.com/login with the login-data of its human owner. It gets a session-cookie (is that even possible in a non-browser environment like pure PHP-scripts?!) and the portal logic knows which URLs are accessible and which not (like for a human visitor).
Any other/better ideas?
I tend to use solution 2 as it's relatively easy to implement and hopefully secure (lets pretend a sha512-string as URL-parameter). Do you have any better suggestions? Mind, that the other way round is not possible, the portal can not actively push data to the machine (as it has no fixed IP, no webserver, ...)

If the device supports cryptographic functions, PKI can be used. Encrypt the data using the device public key. Only the device knowing the private key can decrypt the config file. PKI supports authentication also. here the device connects to a login portal that requests client certificate and after authentication of client, the config file is send to the device encrypted in device public key.
cons: each device requires a client certifcate.

Related

Can I send a message to a certain IP+MAC addr to a machine if I get those addrs by ipconfig?

I'm new to web programming and currently working on LAMPP, I wanna have a try on writing some private msg app, and heard from some forums that I can send a msg to a certain machine once I get the correct IP+MAC addrs, but I don't quite understand where to start, should I rewrite the packet head files? If so , should it be transportation layer work or application layer?
I think you're over-thinking it greatly by going to the IP/MAC layer.
The normal way to do a private messaging app would be to just do something similar to what a browser chat app would do to keep things confidential. It connects to a central server (the web server) using SSL/TLS encryption and stores a message there. The recipient would connect in the same way to fetch the message.
In case you want to add encryption on top of that so that nothing stored on the server can be decrypted, you need some other way to distribute user generated keys (for example, the clients generate a local key and give the public key to the server, then the other users can ask the server for the user's public key)
The reason going to the IP/MAC layer makes no sense is that all messages sent will jump through multiple machines to get to the right place on the Internet, without encryption any of those machines can read the message.

Web based login using ssl public/private key?

Is it possible to create a login process that requires a public/private key through a web browser? The public key would be stored on the server and the private key would be kept (and encrypted) by the user.
I basically want to do something similar to what SSH does, but through the web. Perhaps a custom method of HTTP Authentication (other than "Digest").
I know that it may not be possible to do this with a stock browser, so extensions to make this work are acceptable (Chrome/Firefox).
The keys would ideally be encrypted on a USB Stick. When the USB stick is unplugged in has to be impossible to login (don't want the browser to cache it).
This would be used internally.
Edit: Client certificates would be what I'm looking for, but how do I store these certificates on a USB stick? Also, is there information on how to authenticate a user using PHP?
This is Client authentication via certificates.
Your server should be configured to require a client certificate and also be configured with a truststore.
All the browsers support this.
You just have to import the client keystore having the private key and certificate to the machines set of certificates.
For windows it is in internet options
I doubt you'll be able to do this with a web application. The browser is sandboxed from the operating system and you would be unable to have the web application detect the presence of a USB drive nor would you be able to read any data off of it with the web application. So you would need the browser to do that for you, and they are not designed to work that way.
When you load a client cert into the browser it gets loaded into certificate storage. Those are different depending on browser and OS. On OSX they go into KeyChain. On Windows some will go into the OS key store and some will go into the browsers own keystore (Firefox I believe works this way). But none of them will allow you to define an external keystore and then encrypt and decrypt the key you're trying to protect as it reads and writes from that drive.
What you are doing would only be possible if you wrote your own desktop application (essentially your own browser) that did this for you.
It is possible you could do it with an Adobe AIR application. Adobe AIR supports reading and writing from a USB drive, it supports encrypted databases (128-bit AES/CBC crypto with SQLite) where you could store the data you are trying to protect, and it's cross-platform.
With any of these solutions you will likely be stopped at the requirement of need to ensure the USB key is plugged in. That is likely tough to do. How would you stop the user from simply copying the files from the USB key to the hard disk and then using the key from there so that they did not need to use the USB key?
To get to that level of control you may need to look at a truly native solution. C++, Objective-C, or Java. Java is going to be the only one that offers you a cross-platform solution.
If the USB key is a convenience to the end user as opposed to a requirement, then Adobe AIR would be a solid solution. If not, then it's time to brush up on your desktop software development skills.
Here is how I did web based login using RSA public/private key in php:
On registration, server saves user's public key and gives user an ID
On login, user is asked to enter his ID and private key
Registration is very simple.
But login is done in this way:
Server generates a string that contains some data: random string, current time, user's ip
That string is encrypted twice with AES with two passwords: nonce1 = pass2( pass1( string ) )
Same string is encrypted again with AES with two passwords, but in reverse order: nonce2 = pass1( pass2( string ) ) and the result is encrypted with user's public key: nonce2encrypted = encryptPubKeyRSA( userPubKey, nonce2 )
P.S. The string is encrypted with two passwords, to be harder to make a brute force attack.
The login form contains three hidden inputs: nonce1, nonce2encrypted, and nonce2 without value.
Then the user is asked to enter his private key in a textarea that is outside <form> tag (to be sure that it will not be sent to the server on form submit), a javascript will decrypt nonce2encrypted and set decrypted value to nonce2. Then the textarea with private key is removed from html with javascript, just to be sure it will not be stored somewhere in the browser or sent to the server.
The server receives nonce1 and nonce2, and decrypts them with that two passwords. If the decrypted values are the same, the user receives a cookie and is logged in.
P.S. That cookie also contains some encrypted data, for example user ip. This does not allow somebody that stole this cookie to login from another ip.
You can view this method in action (project on github)
Client certificates are the answer. Most/All browsers import these client certificates as PKCS#12 (.p12, .pfk).
You can convert an existing x509 certificate to a PKCS#12 file with the public key (.crt), private key (.key) and CA certificate (.crt). You can do this with OpenSSL using the following command:
openssl pkcs12 -export -out client.p12 -inkey client.key -in client.crt -certfile ca.crt
If you self-sign your certificates it's important to make sure the certificate serial is different than other certificates. If they are the same you can experience errors trying to import the .p12 file (So watch out for -set_serial in openssl examples).
Unfortunately the only cross-platform way to make certificates mobile/removable is to use a smart card (using PKCS#11).
On Mac OS X Safari and Chrome access their certificates from the keychain. You can actually create a custom keychain on a USB flash drive (File -> New Keychain). After you've created the keychain you can simply drag your .p12 file into your Keychain. What's nice about this is you can control access to what application has access to the certificates, and you can have the keychain itself lock after a certain amount of inactivity.
With Safari this works beautifully. If you unplug the flash drive it stops sending that certificate after a couple seconds. If you plug it back in, it picks it up immediately. If you lock the certificate with "Keychain Access" it asks for the password. It prevents you from properly ejecting the flash drive while in use, but after a minute Safari releases its lock.
Chrome is finicky. It caches the certificate for several minutes. If you lock the keychain, it continues to use the cached version. If you try to properly unmount the flash drive it will tell you Chrome is using it until you close it. If you plug the flash drive in while Chrome is running it won't pick it up.
So it appears that Safari is the only browser to support this. Firefox and Opera both have their own key-stores.
If you want to hide your custom keychain on the flash drive you can create an invisible folder be prefixing it with a period (like "./.keys"). When creating your keychain you can view the invisible folder in the dialog window by pressing Command+Shift+".".
The answer to your question is "not possible today."
The technology is there today in the form of certificates which are supported already in all browsers. But to get what you want, the browsers would have to allow certificates to be added and managed in the "password manager" part of their user interface. People would want to sync them between devices etc.
Additionally, web sites would need similar changes for users to be able to manage the public keys stored on the web site, instead of managing their password.
The benefit of this kind of system would be that you never actually have to send your password (private key) to the web site you're logging in to. But otherwise, you still have all the management activities that you have today with passwords.

How does one install ssl certificates programatically (OpenSSL)

I have an application which I am working on for a client which in summary allows each of their clients to create their own own version of the application by customizing the templates and associate their own domain name (all the code is located on my clients server).
The problem I am faced with is that when such users create their own branded version with their own domain name and then want to login to their admin the system can't provide https authentication.
I am aware that one can create a self signed certificate and I "think" there is a fairly simple way of doing this programatically, BUT if I want to give users the ability to purchase their own CA signed certificate then how could this be accomplished?
I have spent a few hours trying to find the answer to this question online but can't seem to find a solution to this perplexing problem.
What I think I need is some simple code which allow the user to fill out the required form field which in turn creates the CSR file which in turn the user would provide to the CA to obtain his CA file and for which some code would need to allow the user to upload it... Which in turn would automatically install it and redraft the needed web services.
Any/all help and guidance would greatly be appreciated!
How you would go about this depends on your architecture. But here are a couple things to consider:
Most SSL configurations operate on a unique IP address. So that means each SSL certificate you add would require another IP address. You may be able to centralize that configuration if you use a load balancer for example. Whether or not you can do that programmatically depends on your load balancer.
You will be best off generating the CSR based on your private key. Otherwise you will have to allow users to upload both a private key and certificate (and sometimes chain file).
Usually, dealing with the server certificate is done by a system administrator, so few tools will be user-friendly for people with no such knowledge.
You could create a PHP webpage that creates a private key and CSR (see openssl_csr_new examples) and lets the user copy the CSR in PEM format (and the private key for later use). Some CAs will let you paste such a CSR into their form, when requesting the certificate. Once the user gets the certificate (and perhaps the chain from the CA), they'd need to configure the server to use it (along with the private key). Tools like Webmin can let you do this from a web browser (you may want to implement something similar to what Webmin does for this, if you don't want to deploy a full web-based administration interface).
If the task of requesting the certificate is your client's responsibility (which it should really be if it's their server), they will need to be trained a little to know what to do, since the procedure will inevitably vary slightly depending on the CA they choose.
Needless to say that, if you implement scripts that can let the user change certificates and private keys, appropriate authentication and authorization should be used to perform these operations.

PHP digital sign a PDF file using USB token

I want to sign the PDF using client certificate. It only work when I got the file is stored in my PC. Since I want to sign my PDF by using the certificate stored inside a USB token, what should I do to achieve that.
I tried to search from the internet, but all I got are mostly using JAVA. Is there anyway to achieve the same goal using PHP? If not, can anyone provide an alternative way to sign my PDF.
Are you talking about a PHP application that's running on a web server, and the USB token being attached to your client machine? Then forget it; it won't work because you cannot access the client's USB port from your web server via the client's browser without further plugins.
The java apps you're talking about are running in the client's browser and thus may have access to the usb port.
The task is tricky but doable. You need to create a client-side module, then calculate the hash of the document on the server, send it along with the client module to the web browser (by including it into the web page) and have the client-side module sign the hash. Then send the hash back to the server.
Our SecureBlackbox product does this, but it's not currently available for PHP on the server side (we plan to release library edition with PHP binding somewhere next year).

Persistent login info from server to server

I am currently working on 2 web servers, One Coldfusion and the other PHP.
Right now, the Coldfusion server is my main server where users log in to access restricted data.
However, I have also begun using a PHP server and want to make it transparent for users to access a specific page on that server - that server requires log in information as well.
I do not want the users to log in twice.
Is there a way to accomplish this ?
Thx
UPDATE: Working in an Intranet environment, so I can't use any public solution.
UPDATE: Reason I am asking for this is because we are moving from a MSQL / Coldfusion environment (Initial server) to a PHP / ORACLE (new server). So I have 2 user tables as well (although they contain mostly the same information).
I am trying to faze out the use of our initial server in favor of our new server transparently to the user and thus I have to work in parallel for the time being.
Most single-sign-on solutions work a bit like this...
Main system authenticates use
User opts initiates a need to move to system 2
Main system authenticates the user with system 2 in the background
System 2 supplies a random, long and disposable token to Main system
Main system redirects the user, with the token, to system 2
System 2 checks the token (and other factors such as IP address) to validate the session
System 2 disposes of the token to ensure it can't be replayed
You would want to ensure that the transmission channels had some security on, especially where Main system and system 2 are talking to each other. You would want that to be a secure transport.
Store sessions in a database, and share them between the two apps.
You could use xml-rpc to get user data and log the user into the other site when they have a login cookie for the first one and vice versa.
Php manual page for XML-rpc
Here is what I have done, in running my own game server, had users on sql server, and on mysql, and wanted to integrate them both.
I made sure that if a user was created on 1 system, was also created on the other.
So you can modify code in both applications, to automatically create a user in other system if it is created on here.
Depending if both servers share a domain, can you do cross-domain sessions or cookies...But my best guess is to store and retreive data...
Or..
as a person logins/registers record their current ip address, on both servers, then check if this person was on the other server within 2-5 minutes, if so, use the ip address to identify them....
This system is tricky because timing is important, so your not leaving a huge hole in your security....But for short term, going between servers, this is simplest solution, in my own opinion.
Good Luck.
If you are on an intranet, you can actually sniff out the network username of the user from the PC they are logged into the network on using PHP. This assumes that:
You are using IIS to host your PHP application.
Your users are using Windows.
Check the section "2.2 Enabling Support for Detecting Usernames" here.
After that, all you need to do is investigate if the same is possible from Coldfusion, and you have the basis of an SSO solution based on the network usernames.
How about implementing an OpenID solution, much like the one apparent on StackOverflow?
You may benefit from dropping a shared object on the client machine via Flash or Flex. This object could then be read from ColdFusion/PHP/Python on servers that otherwise had no connection to each other or access to a common database.
Here is a simple example from the Adobe Docs
Maintain local persistence. This is
the simplest way to use a shared
object, and does not require Flash
Media Server. For example, you can
call SharedObject.getLocal() to create
a shared object in an application,
such as a calculator with memory. When
the user closes the calculator, Flash
Player saves the last value in a
shared object on the user's computer.
The next time the calculator is run,
it contains the values it had
previously. Alternatively, if you set
the shared object's properties to null
before the calculator application is
closed, the next time the application
runs, it opens without any values.
Another example of maintaining local
persistence is tracking user
preferences or other data for a
complex website, such as a record of
which articles a user read on a news
site. Tracking this information allows
you to display articles that have
already been read differently from
new, unread articles. Storing this
information on the user's computer
reduces server load.
Full Information: http://livedocs.adobe.com/flex/3/langref/flash/net/SharedObject.html

Categories