I'm writing a method that make it possible for my Java program to create a database connection that will eventually make me able to access it from other classes/methods.
public class DatabaseConnection
{
private Connection databaseLink;
public Connection getConnection()
{
String url = "jdbc:mysql://localhost/DBname";
try
{
Class.forName("com.mysql.cj.jdbc.Driver");
databaseLink = DriverManager.getConnection(url, "fakeUsr", "fakePsw"); //these are not the real username/password
}
catch (Exception e)
{
e.printStackTrace();
}
return databaseLink;
}
}
I've got a couple of issues:
1)people not using my computer will not be able to get into my server since I wrote "localhost":
String url = "jdbc:mysql://localhost/DBname";
2)I've typed the real username and password instead of "fakeUsr" and "fakePsw".
The thing is: I'm quite sure that the average user of my program should NOT be able to access that information. Is there any other way to permit access to a DB without making username and password readable by virtually anyone getting access to my source code?
For issue n. 1: I tried to type my IP address instead of "localhost" here:
String url = "jdbc:mysql://localhost/DBname"; //changed localhost to my IP address
but then I get "Communications link failure".
For issue n. 2: I have literally no idea how to solve this. I've never coded a program that needs access to a DB so I had to improvise a bit for that.
About Issue #2:
There is no secure way of storing the password inside the code itself. You can of course try to encrypt the password, but then your code has to decrypt it when the connection is established and therefore the encryption key is visible virtually "to all that have access to your source code". With this key, it is possible to get to the real password, just a little bit more complicated.
The only secure way is to have the user enter the login credentials by his own. Either low level (program arguments when starting your application) or by some form of "login dialog", if the application has a GUI.
A third option would be to create a technical user with restricted DB access, depending on the application you are working on. But this usually causes security issues.
You could create your application such that it sends an https request and authenticate itself against a webserver. What you use to authenticate is up to you: Client IP, username, password, client certificates, ...
Once authenticated, your webserver could transfer a one-time username/password that the client uses to login into your database.
The advantage here is that you can still control whether the user gets full or restricted access, or gets no password any more for whatever reason. And there is no security hole in your application.
1) Most Internet providers don’t allow ordinary users to accept incoming socket connections, both for security reasons and because the network traffic can quickly overwhelm consumer grade networks. You will have to either purchase a commercial Internet connection which allows incoming connections, or look for a server you can lease or borrow. I’m afraid I don’t know what options are available.
2) As MrFreeze correctly pointed out, there is no way to safely embed credentials in an application. No matter what you do to obscure your database login credentials, someone can always decompile your program and figure out how you are decrypting those credentials. The only truly safe solution is to tell users you trust what the credentials are, then write your application so the user must enter them.
Side note: Class.forName("com.mysql.cj.jdbc.Driver"); has not been needed for many years. You can remove that line.
Related
I've designed ForgotMyPassword.java jFrame Form on NetBeans IDE 8.2
wherein I'm using phpMyAdmin for fetching the E-Mail Address of registered users from it and sending it to their E-Mail Addresses through MYSQL Database using JavaMail
I basically want to fetch the E-Mail Address of registered users from it and send it to their E-Mail Addresses through MYSQL Database using JavaMail as One Time Password (OTP) recovery option
Here's the source code :
String username = usrnmfield.getText();
String email = emailID.getText();
String[] to = {"emailaddr#gmail.com"};
Connection conn=null;
PreparedStatement pstn = null;
try {
Class.forName("com.mysql.jdbc.Driver");
Connection db = DriverManager.getConnection("jdbc:mysql://localhost:3307/app" , "xxxx" , "xxxx");
pstn=db.prepareStatement("select * from register where USERNAME=? and EMAIL=?");
pstn.setString(1,username);
pstn.setString(2,email);
ResultSet i=pstn.executeQuery();
if(i.next())
{
if(JavaMail.send
("abc#gmail.com",
"xxxx",
to,
"Hello world",
"Thank you for reading my post"))
{
JOptionPane.showMessageDialog(null , " Please Check out your Inbox for any Password sent by us to you ");
}
}
else if (usrnmfield != i && emailID != i)
{
JOptionPane.showMessageDialog(null, "Wrong Username or E-Mail ID");
}
} catch(HeadlessException | ClassNotFoundException | SQLException e) {
JOptionPane.showMessageDialog(null, e);
}
}
Some remarks and adjustements that could help:
Concerning your application design you should strongly consider another architecture. It is far not recommended to let a client (desktop) app work directly with the SQL database for security matters. Implementing the whole security on the client-side is obviously a bad idea (and will get bypassed easily) as well as it will be unmanageable. Consider using a centralized secure database on a distant also secure server that provides state-of-the-art authentication and authorization mecanisms (eg. through REST-API over HTTPS). Server-side security frameworks include Keycloak, SpringSecurity, Apache Shiro, JaaS... By searching the Web you will see that your design is not so common. Moreover for OTP the use of a Web server or simply remote exchanges seem obvious (and you will need them). You may also consider implement logging through a centralized LDAP server.
Name your fields in the select statement. Eg. "select password from register where ..." so that you know what you expect in order OR use the field name when using select *:
ResultSet rs = ...
String myValue = rs.getString(1);
String myValueBis = rs.getString("password");
Always surround your database queries with a try-finally block in order to close your ResultSet, the prepared statement and eventually the connection (if not reused) and preferably in this order.
I don't see the purpose of this condition:
else if (usrnmfield != i && emailID != i) { ...
You are comparing text fields against a ResultSet but neither the value contained in the text nor the values of the current row of the ResultSet (cf. 1). This makes no sense.
If you want to allow you user to retrieve its password based on its username or its e-mail you should consider using an "OR" (instead of "and") in your SQL statement.
When using JavaMail you must make sure that your Session contains enough information to send an email. It is generally the first step in any JavaMail app to create a javax.mail.Session object. So you need to configure the smtp server or relay, eventually the port and authentication. As you don't show the code of your JavaMail class I suggest you put it in your original question if you have any issue about it and clarify what is the problem (if any).
Generally speaking if you consider using this app for commercial use or some serious purpose you should also quickly think about storing your passwords in an encrypted way (eg. as SHA-256). And also think about not sending the password via E-mail (it will out come naturally if you only store the hash of the users' password...) but instead propose them a secure way to reset/renew it.
I think you should update your question with more code (more finalized and cleaner preferably) and be more precise about your issue. I would not be surprized that a moderator flags your question as too "general" or obscure.
I have a server which allows RMI connections. It exposes a "Server" object on the registry for remote calls, which has a method "authenticate". That method, if successful, returns a "user" object. This user object can then be used by the client to get some data.
It looks like this:
RMIServer server = new RMIServer ();
Naming.rebind("rmi://"+ hostName +"/" + AUTH_OBJECT_BINDING, server);
RMIServer then has a method:
public InterfaceUser Authenticate(String username, String password);
This method checks the username/pw and returns a user object (actually the interface). The user object saves some string which contains the username, and a list of permissions. This can then be checked when calling other methods further down the line.
My question is this:
Someone wants to develop a (another) client for the server, to do this I would give them the interfaces required to interact with it (e.g, the InterfaceUser interface, as well as others). I would need to set up a fake "development" server somewhere to allow them to do this, which they can connect to. Is it possible for that developer to use the interfaces to allow it to get an instance of "InterfaceUser" from the real server without correctly authenticating? For example, Bob logs in to the real server, the server creates a User object which implements InteraceUser. Can Alice, with the interfaces, hijack that object or find it somehow on the registry? All other objects are exported on the same port (if this makes a difference).
Or, can Alice authenticate with the fake server, then somehow use that to access the real server? Let's assume that all usernames/passwords are different on the "real server" and the "development server"
Thanks, any help is appreciated.
Alice can't get any user object unless she can login to a server that provides it.
Any user object Alice does get is bound to the server that created it, and can't be used on another server. It doesn't even survive power cycling of the correct server.
Does that answer your question?
I have written an Android game. Now, I want to connect the marks of the players.
The code below is the client side program, which send their names, countries and marks to the server. Basically, I use ':' to separate the information.
However, hackers can know my server ip and port by decompiling .apk file. Then, they can create a basic java application to access my server. They could send me "hacker:badserver:123456789". Finally, the top mark becomes "123456789".
Is it more secure method to connect user's data?
Socket client = new Socket(ip, port);
OutputStream outToServer = client.getOutputStream();
DataOutputStream out = new DataOutputStream(outToServer);
out.writeUTF("Hacker:HK:3910");
Hackers do not need the APK to ascertain your server's IP. They could simply use a proxy tool such as Fiddler or packet sniffer.
During my brief stint as a game developer (working on the network multiplayer features), you learn to just assume that cheaters and hackers have the source code to your game. Then you design your protocols around that assumption.
So how do you guard your server from being hacked by a rogue client or from cheating? You really can't, but here's some things that make it extremely hard.
Require the user to "log in" (name/password) from the game before allowing it to post anything to your server. If you catch someone cheating, ban their account from playing the game by disallowing them to login. Use a "ticket" or auth token in the header of each HTTP request for the server to validate. If you ban someone, it will be too annoying for them to get a new account to try again.
HTTPS instead of HTTP. Technically a hacker could beat this by simply changing his rogue client to post with HTTPS as well. He could reverse engineer the protocol by debugging your APK. But now you've made it so much harder for him to discover what the protocol is to begin with. With HTTPS, the hacker can't use an easy tool such as Fiddler to observe the network traffic.
Be wary of debug spew in release builds. Make sure your "Log" statements related to anything protocol wise are in debug builds only, never release builds.
Obfuscate everything and use something like HMAC to "sign" every message with a key. This technically isn't security, but will make it A LOT harder for anyone who breaks the encryption to continue. Something like the following:
Example
code:
name = BASE64("Hacker");
messagetype = ROT13("HK");
score = 3910;
tosend = name + ":" + messagetype + ":" + Integer.ToString(score ^ 0xAAAAAAAA) + ":";
Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
mac.init(Your_Secret_Key);
byte[] rawHmac = mac.doFinal(data.getBytes());
tosend += Encoding.EncodeBase64(rawHmac);
Where "Your_Secrey_Key" is encoded somewhere in your source code, and only decrypted at runtime.
The above will generate a string resembling the following:
SGFja2Vy:UX:AAAAA5EC:blahblahxyxunreadable
The corresponding server code will decode the message and validate with the secret key before accepting.
Is this perfect security? No.
Should I build an ecommerce solution with these techniques? Definitely not.
Do these techniques ward off 99% of the casual hacker that might be tempted to do cheat? Absolutely.
Does it beat the most determined of hackers that are out to win the high score at all costs? Maybe not. But the "effort to reward" ratio goes way up. It may not be worth their time.
Hope this helps.
I need to restrict specific user's roles to use the application while are accessing it from a specific place lets say "Users with role employee can only access the application from the office or its branches"
IP checking? it is changeable
How about if I follow private/public key? the disadvantage of that is that if I put the key in the cookie they can read it or may clear their cookies.
Based on mac address ? it is changeable
You can't trust IPs and MAC addresses are even more useless, your only friend here is cryptography. Assuming your user will authenticate using his credentials you need to somehow authenticate the machine as well. This is done by placing a different certificate on each machine and having the client prove his "identity" to the server by using his certificate.
If your client-server communication is based on SSL, you can require client authentication - have a look at Java HTTPS client certificate authentication, http://rap.ucar.edu/staff/paddy/cacerts/ or http://docs.oracle.com/cd/E11035_01/wls100/security/SSL_client.html.
If your communication is not based on SSL, or you wish to authenticate on the application level - you can still use the certificate. Load it from the truststore and prove your identity by proving you have access to the private key (usually the server sends a challenge, something random encrypted with the public key, you answer by decrypting it with the private key and sending it back. That way you prove you have the private key without having to show it).
If you do not wish to store certificates, you can just place a different encrypted file on each machine. The client will be able to decrypt it (using a hard coded key) and send something akin to a password to the server.
How do you protect these certificates? Read-only permissions for the users on the file...
Several notes -
You can't really EVER trust a client machine. A resourceful hostile user will break anything. The more resources you "enemies" have the more effort you need to put into your defence.
You didn't specify details regarding your environment. I'm sure there are system level solutions which I'm not aware of. For example - your server may connect to the Active Directory and monitor user logins on specific machines.
Sometimes the best solution may not come from the software level. For example, if your server uses a designated port for your communication. You could allow\block this traffic on your firewall\router\personal firewall - in places more adequate to resolve this issue than your server. If you have application control enforcement, you can allow the client itself to run on only specific machines.
You can also look for ways to create some unique PC fingerprint (motherboard Id, cpu id, SID in Active Directory, HDD id, MAC address...) - your server could then store a list of allowed fingerprints and your client will send the currently calculated fingerprint. This still comes back to - how well do you trust your clients?
Restricting by IP only works if people are coming from places that have static IPs. Anywhere like at home where you have dynamic it doesn't work.
If you can't use static and still want to restrict by IP you could use a service like http://dyn.com/dns/ to assign a FQDN to your IP. Then you could do lookup by FQDN to see if it returns an IP that matches the one in the request. This lookup could be cached so you're only doing every few hours. The tricky part to this is that each location would have to setup of a dynamic DNS client. Some routers now have this built in.
You can't get the MAC address through the HttpServlet class. And if could you'd get the MAC address from the device that is talking to your server which most likely would be something like a router, load balance, switch. MAC address aren't not route'able.
Re: Keys, you can use x509 certs - http://static.springsource.org/spring-security/site/docs/3.0.x/reference/x509.html
I just want to address this part of your Question:
I am trying to implement the IP method but it runs into following error.
java.lang.IncompatibleClassChangeError: com.project.Default and
com.project.Default$IpCheckService disagree on InnerClasses attribute
An IncompatibleClassChangeError means that there is a conflict between what the types were at compile time and what they are at runtime. In this case, it seems to be that you have (had) a nested IpCheckService class that has changed from static to non-static (or vice-versa!), and somehow you've managed to load an old version of one of the classes.
This is a build or deployment problem. If you can figure out what is going wrong here there is a good chance that your code will work. (At least, you won't get this exception any more.)
UPDATE:
The only way to restrict users in a certain place is the following:
You must define Fixed IP's in the Office!
Or, at least, a subnet mask for the office and it's branches.
In your application, check the subnet mask from the request and compare it to fixed preconfigured office subnet mask.
Thus, either you put those fixed IP's into webconf.xml or the subnet mask for the IPs;
In any event, the solution will always be connected to a network solution.
You could try something like this to check a fixed IP:
public class TestFilter implements Filter{
public void destroy() {}
public void init(FilterConfig arg0) throws ServletException {}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filter) throws IOException, ServletException
{
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
IpAddressMatcher matcher = new IpAddressMatcher("192.168.1.0/24");
try {
if(!matcher.matches(req.getHeader("X-Forwarded-For"))){
res.sendRedirect("AnotherPage.jsp");
}
} catch (UnsupportedOperationException e) {
//Handle IT
}
}
}
Also, you may need check the following, to catch every situation:
request.getHeader("Proxy-Client-IP");
request.getHeader("WL-Proxy-Client-IP");
request.getHeader("HTTP_CLIENT_IP");
request.getHeader("HTTP_X_FORWARDED_FOR");
request.getRemoteAddr();
I've found the following code from here, you can identify them based on their mac address.
This one is also helpful.
package com.mkyong;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
public class App{
public static void main(String[] args){
InetAddress ip;
try {
ip = InetAddress.getLocalHost();
System.out.println("Current IP address : " + ip.getHostAddress());
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
byte[] mac = network.getHardwareAddress();
System.out.print("Current MAC address : ");
StringBuilder sb = new StringBuilder();
for (int i = 0; i < mac.length; i++) {
sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? "-" : ""));
}
System.out.println(sb.toString());
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (SocketException e){
e.printStackTrace();
}
}
}
To set up such kind of authorization rules, the first thing need to be defined is:
What is the definition of "office or its branches" in terms of computer identification?
Usually it is computers from some subnetwork as written in answers above - in that case the solution is obvious.
Second possibility - some guy came to the office with his personal computer or laptop or touchpad, etc. If this is allowed by security policy, the only entity we can authenticate is user. We might still want to differ access from the office (as physical location, e.g. building)/from home. In that case I'd recommend to look at one-time-password generation devices that should be available to user only in the office.
"Users with role employee can only access the application from the office or its branches"
Use a site-to site VPN. This effectively transforms the problem into an intranet login problem, which is trivial to solve.
By having a site-to-site VPN, you can be assured of the identity of the remote sites, since connection setup and authentication is generally performed by routers on site, the configuration of which users at the site do not need to know (or have on their computers, so cannot take away).
Once transformed into an intranet problem, just bind the application to an intranet address and secure it as you would any other intranet resource.
I am creating an application and I need to connect to a database. The database requires login/password so the application can do operations like select and insert.
In the application I need to connect to the database using login and password, so the application is free to do some tasks on the database. My question is: how do I store and use a password to connect to the database without exposing the password?
I can't simply use a hash or encryption to store the password because the database must recognize the password (I think most or all databases must receive password as plain text).
.
.
Note: The connection is made by the application. No human input to do the connection.
(Edit)More info about the application: it is a web application using servlets/jsp. The database is on the same server of the application. The user for the application is a default user without complete admin powers, but it may insert/delete rows and do most things that involve queries and data modification in tables.
The usual way this is done is to externalize the username/password to a property/config file which is read at runtime (whether or not you use native JDBC/JNDI/CDI/J2EE datasource/etc).
The file is protected via the O/S security by the sysadmins.
The O/S has better tools for protection than app code.
You can use jasypt for the encryption.And store the username and password to datasource.properties file.
public Connection getConnection() throws IOException{
try{
BasicTextEncryptor encryptor = new BasicTextEncryptor();
encryptor.setPassword("jasypt");
Properties props = new EncryptableProperties(encryptor);
props.load( this.getClass().getResourceAsStream("datasource.properties") );
String driver = props.getProperty("datasource.driver");
String url = props.getProperty("datasource.url");
String userName = props.getProperty("datasource.userName");
String password = props.getProperty("datasource.password");
Class.forName(driver);
Connection conn = DriverManager.getConnection(url, userName, password);
conn.setAutoCommit(false);
return conn;
} catch(ClassNotFoundException e) {
e.printStackTrace();
return null;
} catch(SQLException e) {
e.printStackTrace();
return null;
}
}
You should use a config file for this. use spring with JDBC to make your life easier!
http://www.youtube.com/watch?v=f-k823MZ02Q
Checkout the above awesome tutorial on the Spring framework and using JDBC. Watch all of his JDBC and spring tutorials.
BTW, he covers how to store passwords in config files and wire beans etc.. Hope this helps.
If it's a web app, deploy it on a Java EE app server and connect using a JNDI resource. Only the admin who set up the JNDI data resource needs to know about the credentials needed to connect. Users and developers don't even have to know them; just the JNDI lookup name.
It's not possible to completely eliminate the need for someone besides the database owner to know the username and password, but it is possible to restrict that knowledge to the app server owner.
You are also well advised to create separate credentials just for that application and GRANT it the minimum access and permissions needed to accomplish its tasks. There should be no knowledge of system tables or any other resources outside the province of the application. IF DELETE permission isn't necessary, don't grant it. If access should only be read only, that's what you should GRANT to that credential.