We have a Rest API that requires client certificate authentication. The API is used by this collection of python scripts that a user can run. To make it so that the user doesn't have to enter their password for their client certificate every time they run one of the scripts, we've created this broker process in java that a user can startup and run in the background which holds the user's certificate password in memory (we just have the javax.net.ssl.keyStorePassword property set in the JVM). The scripts communicate with this process and the process just forwards the Rest API calls to the server (adding the certificate credentials).
To do the IPC between the scripts and the broker process we're just using a socket. The problem is that the socket opens up a security risk in that someone could use the Rest API using another person's certificate by communicating through the broker process port on the other person's machine. We've mitigated the risk somewhat by using java security to only allow connections to the port from localhost. I think though someone in theory could still do it by remotely connecting to the machine and then using the port. Is there a way to further limit the use of the port to the current windows user? Or maybe is there another form of IPC I could use that can do authorization using the current windows user?
We're using Java for the broker process just because everyone on our team is much more familiar with Java than python but it could be rewritten in python if that would help.
Edit: Just remembered the other reason for using java for the broker process is that we are stuck with using python v2.6 and at this version https with client certificates doesn't appear to be supported (at least not without using a 3rd party library).
The most simple approach is to use cookie-based access control. Have a file in the user's profile/homedirectory which contains the cookie. Have the Java server generate and save the cookie, and have the Python client scripts send the cookie as the first piece of data on any TCP connection.
This is secure as long as an adversary cannot get the cookie, which then should be protected by file system ACLs.
I think I've come up with a solution inspired by Martin's post above. When the broker process starts up I'll create an mini http server listening on the IPC port. Also during startup I'll write a file containing a randomly generated password (that's different every startup) to the user's home directory so that only the user can read the file (or an administrator but I don't think I need to worry about that). Then I'll lock down the IPC port by requiring all http requests sent there to use the password. It's a bit Rube Goldberg-esque but I think it will work.
Related
I am student and I am actually new to Javafx or java world, but I like programming...
In my room I have an old computer, I made it as a Server for test. (Ubuntu Server Operating System).
In this Server, I installed Apache at port 80 and Tomcat at port 8080.
Now I have developed very simple Login GUI using Javafx. Now I want do "Login in" or "Sign up", I have 4 ideas(questions) and 1 Problems:
Client-Side:1 Problem
User click "Login in", what is the normal way to do such a request? I mean, I should firstly get the username and password; and then MD5(password); and then username.getbytes(), password.getbytes(); and then java Serialization; then transfer them to server side. Am i right? or should I need some cryptograph in the transfer process?
Serve-Side: 4 ideas or questions
The Server (my old Ubuntu server computer) get the request from Javafx GUI Application. Then how can I make such things, and response?
I mean:
If I want using Java Codes to handel the request under Http Apache Server (port 80), what should I do? I mean, write a Java Programm, and then how run it in Http Server? If a use PHP, will it the same?
If I want using Java Codes to handel the request under Tomcat Apache Server (port 8080), what should I do?
If I self write a Java Programm at some any port (e.g. 9999), something like: while(true) serverSocket.acceppt();}(at port 9999 e.g.) , what should I do , I should run it under Tomcat or Apache? Or what should I do? I really do not know....
If I want using Apache to forward the request to tomcat, I should use somethink like mod_jk or mod_proxy, right?
I need some help about one Concept or direction.
Client-Side:1 Problem
The normal process of using the authentication is to store the user passwords on the server and then every time the user wants to login, the server matches the password against the already stored password in the server. If it matches, then the user session starts.
You can have your password stored on the server as plain text (not at all recommended) or in encrypted form. If you decide to store it in the encrypted form then every time the user provides the password, you must encrypt it on the client side using java script encryption libraries and match it against the password saved on the server. For sending the encrypted password to the server you can use either ajax (e.g. JQuery) or just HTML submit method.
Serve-Side: 4 ideas or questions
The Server (my old Ubuntu server computer) get the request from Javafx GUI Application. Then how can I make such things, and response? I mean:
If I want using Java Codes to handel the request under Http Apache Server (port 80), what should I do? I mean, write a Java Programm, and then how run it in Http Server? If a use PHP, will it the same?
If you decide to build your server with Java language, then you can only have tomcat server (which is actually a servlet container). Each request on the server (such as for user login) is handled by a backend servlet which receives the HTTP request from the client side and performs the required operation. You can also write JSP.
If you decide to use PHP then you only need apache server and not tomcat server. For php, every request is handled by a PHP file on the server.
If I want using Java Codes to handel the request under Tomcat Apache Server (port 8080), what should I do?
If I self write a Java Programm at some any port (e.g. 9999), something like: while(true) serverSocket.acceppt();}(at port 9999 e.g.) , what should I do , I should run it under Tomcat or Apache? Or what should I do? I really do not know....
Writing a customer java program which listens to HTTP request on a specific port is called a server program and apache or apache tomcat are nothing but these program already written and provided for free. So, only in very specific situation you might decide to write your own but for sure having a login authorization doesn't require it.
If I want using Apache to forward the request to tomcat, I should use somethink like mod_jk or mod_proxy, right?
This is don't know.
I have a server application and a client application created with java that will communicate with the server application. But, since i haven't put emphasis on security in the server side it is really easy to hack the server application if a hacker creates his own client to connect with my server. I want to make sure the client application that is communicating with my server is the authentic client that i created. I upload client to a specific host like www.abcd.com. Now, can i make sure when a client that connects to my server came from that host. I am knowledgeable about signing it with trusted signer but i am looking for a cheap option.
No, this isn't possible. If it were, DRM would work, but everyone knows it's hopelessly broken.
To be truly secure, the client has to be a machine with a "trusted platform module," TPM, that supports something called remote attestation. This allows the server to verify the client is authentic and unaltered. But I've never heard of a real world application of this, and though TPMs are common, I'm not sure if the remote attestation feature is.
I want to make sure the client application that is communicating with my server is the authentic client that i created.
You have two options. One is a password or shared secret, and the other is client certificates. All three are supported in SSL/TLS. Look for TLS-SRP (password based authenticated key exchange), TLS_PSK (preshared key based on a block cipher), and the traditional SSLTLS ciphers with client side certificates.
You can even set up the tunnel with Server Authentication only, and then perform the client authentication at the application level. This is what usually happens in web apps. But this has some non-trivial defects because it does not provide mutual authentication and lacks channel binding. You are better off with TLS-SRP, TLS-PSK, or client certificates.
EDIT: I focused on SSL/TLS because you cited a hostname, but you can do it at other layers, too. For example, you can use shared secrets and certificates at the VPN level. #erickson provides one method using TPMs that could be used at the application level.
Now, can i make sure when a client that connects to my server came from that host.... host like www.abcd.com
This will work if DNS is configured and trustworthy. That is, you will have to extract the host's name, perform a reverse lookup, and then authenticate the IP address. I believe this is called network based authentication.
If an attacker controls DNS or is on the same LAN segment as the server, then I believe network based authentication has some non-trivial security defects.
In any case, HSMs and TPMs are not the answer. To understand why, see Peter Gutmann's Engineering Security, and the section on Unattended Key Storage. From his book:
TPMs don’t work because all that they can do is store the fixed key
that’s required to decrypt the other keys (TPMs are just repurposed
smart cards and don’t have the horsepower to perform anything more
than lightweight crypto themselves so you can’t offload the overall
encryption processing to them), and since for unattended operation
they have to release their secrets without a PIN being entered they’re
just providing plaintext key storage with one level of indirection.
I need to connect to Unix Server using Java via SSH and SFTP protocol and execute specific commands and do File Transfers also. But there is RSA token authentication is enabled on Unix. So I need to get the current RSA token password at run time also along with User's Password.
So how to get this done
via Java? Is there any Java API for this?
FYI, Unix Login steps using putty :
connect using Server IP.
List item
give User Name.
give Password
give the 6 digit SecurID generated Number.
This sounds like keyboard-interactive authentication. In this authentication mechanism the server asks user a question, to which the user must respond. Any number of questions is possible and their order is defined by the server.
Keyboard-interactive authentication is used by many servers, but it's usually reduced to asking for a password, so most software which claims support for this authentication method will just put a password as the answer and that's all.
I don't know if free Java libraries support keyboard-interactive authentication with multiple questions. Our SecureBlackbox classes have an event which passes questions to the application, and the application can either provide an answer itself or ask the human operator to provide the answer.
JNDI LDAP auth requires a cleartext password to be passed (Context.SECURITY_CREDENTIALS) to almost all security mechanisms (or at least how I understand it). It looks like to be designed in a way, that the password originates from the current JVM. But what about a password, that has to be sent from another machine? This approach forces it to be sent in a recoverable fashion (the most simple is cleartext) with little security.
To be more specific, let's consider a 3-tier setup: client, java server and an LDAP server. The user enters the username and password in the client which is sent to the java server. Then the java server communicates with an LDAP server in order to authorize these credentials. Is there a way to make the transmission from the client to the java server secure?
I understand, that we can use SSL or another way to secure the channel itself, but it's still no good that we have to send the password in a recoverable fashion through this (even secure) channel.
I tried to search for an answer, but it looks like most of them consider a 2-tier setup. There were also some 3d party java libraries recommendations (instead of JNDI), but it wasn't clear, if that they can handle my task. If they actually do so, could you please give an example utilizing them for my task?
My target platforms are Delphi XE3 Client, Java SE 6 Server and an AD LDAP. But I'm also interested in a more theoretical discussion not restricted to these concrete client and LDAP.
This approach forces it to be sent in a recoverable fashion (the most simple is cleartext) with little security.
The approach requires you to use SSL. It's as simple as that.
We found the answer and actually made it work on a production system.
The correct path is to use the Kerberos protocol http://en.wikipedia.org/wiki/Kerberos_(protocol).
In my setup the following happens:
1) The client obtains a ticket to the server service in the AD and sends it to the server. This is done via classes near TSSPIWinNTCredentials class in Indy, but I think it's quite possible to do so without difficulties using Windows functions directly.
2) The server logins to the AD as a service. This is done via LoginContext class using correct AppConfigurationEntry with keys.
3) The server authenticates the client in the AD using client's ticket, obtaining client's username. This is done via Subject.doAs method and classes near GSSManager class.
4) The server performs additional business level checks and grants the client a business session. This is business-specific of course.
At no point in this scenario any insecure communication is made, including sending passwords in a recoverable fashion, because it is the design goal of the Kerberos protocol itself.
I want to implement Single Sign On with Kerberos in Java and have successfully managed to create a ticket for the Service using the ticket from the Windows logon. Unfortunately, I can only create that ticket when the Registry Key "allowtgtsessionkey" is enabled. I am receiving an exception with the message "Identifier doesn't match expected value (906)" as soon as I disable it. The registry key is documented on http://java.sun.com/j2se/1.5.0/docs/guide/security/jgss/tutorials/Troubleshooting.html and http://support.microsoft.com/kb/308339.
Unfortunately I do not have access to the registry on the computers where my application will be used, so I am looking for a way to do this without having to modify it. When I do Single Sign On over SPNEGO in Internet Explorer or Mozilla Firefox, they create a Service ticket in my ticket cache, so there definitely has to be a way to do this without setting the registry key. Does anyone have an idea how to do this in Java?
Thanks for your help,
memminger
Update: I am giving up on this issue. The Windows registry key prevents the access to the Ticket (more exactly: the Subject) inside the Ticket cache. Java on Windows uses its own GSSAPI implementation, and I suppose that needs access to the Ticket to create a Service Ticket. The SSPI Windows API though has full access to the Ticket cache and can thus create Service tickets. This API is used by the web browsers, but it is not used by Java (according to http://java.sun.com/developer/technicalArticles/J2SE/security/#3). When I disable SSPI in Firefox after having accessed a web page once (so a service ticket has been created), I can still access the page, so maybe a command-line util would be sufficient that creates a service ticket using the SPPI API.
For us, this means now that we can either abandon Single Sign On (which is unacceptable for us) or that we do the authentification on the client side of our application (because we can only read out the username but not verify the ticket on the server), which is a major security risk. Another example of how stronger security constraints lead to bigger security holes because they become too complicated to use.
Forgive me if I am misunderstanding you problem, but...
The point of SSO type systems is that the client authenticates directly to the (separate) authentication server, and obtains a ticket from it. It then passes the ticket to the target server(s) it wants to use, each of which verify that the ticket is valid with the authentication server. If the ticket is validated, it can be assumed by the server that the client only obtained it by presenting the (trusted) Kerberos server with acceptable credentials.
Nowhere in the process, should any server authenticate on behalf of the client. In such a system, the only server that needs to know and validate the client's credentials is the authentication server - no other server need have access to this information. This way the client can authenticate for many servers with just one authentication exchange, and credentials are not put at risk by being stored on, or accessible to, multiple servers.
It sounds like your implementation is working just as it should - the authentication should occur on the client side of the application, and this is correct and not a security risk.
Have you tried setting sun.security.jgss.native in Java 6? Wouldn't SSPI be the "native" interface for windows?
You can access the native SSPI API via JNA. See the WindowsAuthProviderImpl in WAFFLE or WindowsNegotiateScheme from the Apache HC library for an example.
Native support for Windows SSPI was introduced into JDK 13 and later backported to JDK 11 too. You'll need to use at least Java 11.0.10. When the JDK's support for SSPI is used then there's no longer a need to fiddle with the allowtgtsessionkey registry key, nor any need to use JNA or Waffle.
You need to set
-Dsun.security.jgss.native=true
to make it work.
You can recognize if your JDK version for Windows has support for SSPI if it includes a file named sspi_bridge.dll in the bin directory.
Refs:
JDK-6722928