I am currently developing a C# WPF application. It is only used by a small amount of people/devices.
To make things easier I decided to talk directly to the MySQL db.
Now I wanted to be able to switch the current User / db Credentials with the click of a button, or be able to implement a logout feature.
I just currently tried this:
public DBConnect()
{
Initialize(null, null);
}
private void Initialize(string uid, string password)
{
string connectionstring;
connectionstring = "SERVER=" + server + ";" + "DATABASE=" + database + ";" + "UID=" + uid + ";" + "PASSWORD=" + password + ";";
connection = new MySqlConnection(connectionstring);
}
public void setCredentials(string uid, string password)
{
Initialize(uid, password);
}
public void destroyCredentialsAndConnection()
{
connection = null;
}
But apparently while Debugging I found out, that the old connection string is still cached statically by the MySQLConnection Class in the background.
Currently it does look like my approach is working, but I'm actually worried about the security of that implementation to list a few concerns:
memory dumps (usage of strings for passwords that can not be encrypted and may not be removed for quite some time by the garbage collector)
memory dumps (the fact that the connection string is being cached even after a "logout")
network traffic sniffing (is the connection between the database and my C# application encrypted)?
physical access to the server (is the MySQL database stored encrypted on the harddrive)?
Is there any better (more secure) way to switch credentials or to completely log the user out?
I did not really find any similar attempts here or anywhere else while doing research.
And if I would try to develop a php backend would that be safer without much experience? And could I still use my audit tables that I have created based on MySQL Triggers?
If I am understanding what you are asking correctly, you could try making a method to build the connection string based on user input, and inject the user's credentials into the connection string each time the method is called.
static SqlConnection Connection()
{
string UserName = UserNameField.Text;
string Password = PasswordField.Text;
SqlConnection Connection = new SqlConection("Server=ServerName,Port;Initial Catalog=Catalog;User Id=" + UserName + ";Password=" + Password + ";");
return Connection;
}
Related
I'm aware there are similar questions all over the web, but I can't find anything for this particular issue. I have C# experience, but am pretty new to MySQL, so perhaps there's something I'm not understanding. I'm trying to make a simple select in C# from a MySQL table:
string server = "192.168.2.6";
string database = "productintegration";
string uid = "root";
string password = "Password1";
string connectionString = "SERVER=" + server + ";" + "DATABASE=" + database + ";" + "UID=" + uid + ";" + "PASSWORD=" + password + ";";
MySqlConnection connection = new MySqlConnection(connectionString);
string query = "select * from tcdidataimport";
connection.Open();
MySqlCommand cmd = new MySqlCommand(query, connection);
MySqlDataReader dataReader = cmd.ExecuteReader();
DataTable dt = new DataTable();
if (dataReader.HasRows)
{
dt.Load(dataReader);
}
connection.Close();
And I get the following exception:
Authentication to host '192.168.2.6' for user 'root' using method 'mysql_native_password' failed with message: Access denied for user 'root'#'JUSTINSPERSONAL' (using password: YES)
Seems simple enough... Except that I'm already connecting to that server (via MySQL Workbench) using that exact login.
Here is show grants;
Which seems to me that I should be able to log in using root at whatever I want? When I tried to create another user (CDISelector#'%') and grant privileges I got a similar error:
But I'm logged in as root? Am I missing something here? Finally, here's the results of select user(), current_user();
JUSTINSPERSONAL is my PC, 192.168.2.6 is the MySQL machine's IP. Not sure what I'm missing here but this all seems a little strange.
And it turns out I had the password incorrect. Ha.
I've written a generic database class which can be called to carry out common database (CRUD) operations to save re-writing the ADO.NET code in multiple solutions. To make this flexible, there are a number of constructor overloads based on the different database authentication types and instance types etc. The class is as follows:
class Database
{
// default instance with Windows authentication
// constructor 1
public Database(string server, string database, bool persistSecurityInfo)
{
_server = server;
_database = database;
_persistSecurityInfo = persistSecurityInfo;
_integratedSecurity = "True";
_connectionString = "Data Source=" + server + ";Initial Catalog=" + database + ";Persist Security Info=" + persistSecurityInfo.ToString() + ";Integrated Security=True";
}
// named instance using Windows authentication
// constructor 2
public Database(string server, string instance, string database, bool persistSecurityInfo) : this(server, database, persistSecurityInfo)
{
_instance = instance;
_integratedSecurity = "True";
_connectionString = "Data Source=" + server + "\\" + instance + ";Initial Catalog=" + database + ";Persist Security Info=" + persistSecurityInfo.ToString() + ";Integrated Security=True";
}
// default instance with SQL authentication
// constructor 3
public Database(string server, string database, bool persistSecurityInfo, string userName, string password) : this(server, database, persistSecurityInfo)
{
_userName = userName;
_password = password;
_integratedSecurity = "False";
_connectionString = "Data Source=" + server + ";Initial Catalog=" + database + ";Persist Security Info=" + persistSecurityInfo.ToString() + ";User ID=" + userName + ";Password=" + password;
}
// named instance with SQL authentication
// constructor 4
public Database(string server, string instance, string database, bool persistSecurityInfo, string userName, string password) : this(server, database, persistSecurityInfo, userName, password)
{
_instance = instance;
_integratedSecurity = "False";
_connectionString = "Data Source=" + server + "\\" + instance + ";Initial Catalog=" + database + ";Persist Security Info=" + persistSecurityInfo.ToString() + ";User ID=" + userName + ";Password=" + password;
}
private string _server;
private string _instance;
private string _database;
private bool _persistSecurityInfo;
private string _userName;
private string _password;
private string _integratedSecurity;
private string _connectionString;
private string _query;
//CRUD Methods here
}
I have written a console application which is writing to a database. When the application is executed, the user provides some command line switches.
Some of the switches are as follows (There are others relating to the program's operation which I have not included here):
/s : database server name
/i : database instance name
/d : database name
/n : integrated security (True or False)
/u : db Username
/p : db Password
/i, /u and /p are optional (EG if an instance name isn't supplied, the program assumes it is to connect to a default instance on /s)
Therefore, I need the program to, at run time decide which constructor to call based on which arguments have been provided.
pseudo example here
Class Program
{
static void Main(string[] args)
{
foreach (string arg in args[])
{
//code to work out which parameters have been provided here and adds them to array. Also other code which checks integrity such as ensuring there is no username without a password and vice versa etc.
string[] suppliedParameters;
//if there is a /i , /u , /p parameters, use constructor 4
//if there is a /u and /p but no /i, use constructor 3
//if there is an /i but no /u or /n use constructor 2
//if there is no /i, /u or /n, use constructor 1
}
}
}
I know I can use reflection to execute the relevant constructor and that I could achieve selection of the constructor using a switch statement in the Main method which carries out the tests in the logic above but am just wondering if there is a maybe a more elegant way to do this?
If you want to use Reflection then, use Activator.CreateInstance method which accepts Type and Array of objects as parameters. It will automatically call required constructor based on number of items in array and item types.
object[] arguments = //Create array based on input
DataBase db=(DataBase)Activator.CreateInstance(typeof(Database), arguments); // This will call matching constructor based on array passed
I suggest a quite simpler approach. Use one single constructor that sets your members appriately:
public MyClass(params string[] switches)
{
if(switches.Contains("/i") this.i = ...
...
}
You can also create a simple list with all the options whose switch is true.
To call this constructor simply use this:
var instance = Activator.CreateInstance(myType, suppliedParameters);
I'm writing a Class Library in C# as an add-on to another application that provides an API. Essentially, the application is set to execute the code in my Class Library upon changing a specific text field in the application. I'm finding that after I change that field once, changing any other text field also triggers my code to run and I cannot figure out why.
The Class Library has a function executed by the application. Essentially, I'm connecting to a SQL Database, calling a Windows Form to show, then disposing of everything. I find that by removing the SqlConnection, the issue does not occur.
Any thoughts would be greatly appreciated.
SqlConnection myConnection;
myConnection = new SqlConnection("user id=" + Username + ";" +
"password=" + Password + ";" +
"server=" + Server + ";" +
"database=" + DBName + ";" +
"connection timeout=" + ConnectionTimeout + ";"
);
myConnection.Open();
string currentValue = htableData["Test"].ToString().Trim();
if (!(String.IsNullOrEmpty(currentValue)))
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form1 form = new Form1();
Application.Run(form);
form.Dispose();
}
myConnection.Dispose();
Any thoughts would be greatly appreciated.
This isn't quite what you asked about, but it is not good practice to call Dispose explicitly. It is best to use using blocks instead.
SqlConnection connection;
using (connection = ... ) {
// use the connection
} // connection is automatically disposed (and error handling is done for you)
Ideally, you should also use the same pattern on the form
using(SqlConnection myConnection = new SqlConnection(
"user id=" + Username + ";" +
"password=" + Password + ";" +
"server=" + Server + ";" +
"database=" + DBName + ";" +
"connection timeout=" + ConnectionTimeout + ";")
){
myConnection.Open();
string currentValue = htableData["Test"].ToString().Trim();
if (!(String.IsNullOrEmpty(currentValue)))
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form1 form = new Form1();
Application.Run(form);
form.Dispose();
}
myConnection.Close();
}
You are not providing enough code to tell why it is called twice. But I do have a couple of comments to make.
This is not the correct way to display a form within and already running application that already displays other UI elements. The correct way is form.Show() or form.ShowDialog(). I guess the latter in your case. Avoid calling EnableVisualStyles and SetCompatibleTextRenderingDefault as well.
To ensure the correct disposal of things (especially when exceptions occur), you could make use of the using statement, even though I don't think that this is the cause of your problem. Here is a nice showcase: Understanding the 'using' statement in C#
Again, it will not solve your problem, but a more elegant way of creating your connection string would be to use the SqlConnectionStringBuilder, instead of concatenating the strings. Here is how: How to use SqlConnectionStringBuilder in C#
I am new to MySQL, I am setting up a database connection to be used for a C# application. I am following a youtube tutorial on setting up this connection, but I am confused on what is a Server name? Is it just the IP Address or do I have to include the company domain name whos providing the server. Would the following be correct?
private void Initialize()
{
server = "xxx.1x4.xxx.15x";
database = "nameOfDatabase";
uid = "username123";
password = "pass123";
string connectionString;
connectionString = "SERVER=" + server + ";" + "DATABASE=" +
database + ";" + "UID=" + uid + ";" + "PASSWORD=" + password + ";";
connection = new MySqlConnection(connectionString);
}
Using the ip adress along with the actual port for the mysql service will work unless security measures have been taken to prevent access.
example : 127.0.0.1:1840
In short, yes, you can use the IP address, although I've always used the hostname.
You might want to check out this question:
Accessing SQL Server using an IP Address and Port Number ... Help!
how to open the btnSMS.PostBackUrl with a new tab / new window? Or is there anyway to go to that URL then automatically go to another page?
More information: That URL is a method to send SMS using service provider (Clickatell). But the URL got nothing other than stating if the message send was successful or not. I don't want the user who use my ASP.NET to stuck there. I want to allow them to go back to my website after sending the message.
protected void btnSMS_Click1(object sender, EventArgs e)
{
String HP = txtHP.Text;
String URL = "http://api.clickatell.com/http/sendmsg?user=myuser&password=mypassword&api_id=myapi_id&to=";
String Text = "&text=" + txtSMS.Text;
btnSMS.PostBackUrl = URL + HP + Text;
string username;
//Sql Connection to access the database
SqlConnection conn6 = new SqlConnection("MY CONNECTION");
//Opening the Connnection
conn6.Open();
string mySQL;
username = HttpContext.Current.User.Identity.Name;
//Insert the information into the database table Login
mySQL = "INSERT INTO Table_Message(Username, Message, Title, SendTo) VALUES('" + username + "','" + txtSMS.Text.Trim() + "','" + txtTitle.Text.Trim() + "','" + txtHP.Text.Trim() + "')";
SqlCommand cmdAdd = new SqlCommand(mySQL, conn6);
//Execute the sql command
cmdAdd.ExecuteNonQuery();
//Close the Connection
}
Your button should closely reflect as below:
<asp:Button runat="server" ID="btnSMS" UseSubmitBehavior="false" OnClick="btnSMS_Click1" Text="Send/>
Then in the code-behind build your postback url and then after the submition add the following:
protected void btnSMS_Click1(object sender, EventArgs e)
{
String HP = txtHP.Text;
String URL = "http://api.clickatell.com/http/sendmsg?user=myuser&password=mypassword&api_id=myapi_id&to=";
String Text = "&text=" + txtSMS.Text;
string UrlFinal = URL + HP + Text;
string username;
//Sql Connection to access the database
SqlConnection conn6 = new SqlConnection("Data Source=19-17\\sqlexpress;" + "Initial Catalog = Suite2; Integrated Security =SSPI");
//Opening the Connnection
conn6.Open();
string mySQL;
username = HttpContext.Current.User.Identity.Name;
//Insert the information into the database table Login
mySQL = "INSERT INTO Table_Message(Username, Message, Title, Startdate, Enddate, SendTo) VALUES('" + username + "','" + txtSMS.Text.Trim() + "','" + txtTitle.Text.Trim() + "','" + txtHP.Text.Trim() + "')";
SqlCommand cmdAdd = new SqlCommand(mySQL, conn6);
//Execute the sql command
cmdAdd.ExecuteNonQuery();
//Close the Connection
this.ClientScript.RegisterStartupScript(this.GetType(),
"navigate",
"window.open('" + UrlFinal + "');",
true);
}
This should open in a new windows. Alternatively one can use window.navigate as well which will open another page in the same browser.
I think a better way to implement this is to make the form post to a URL in your site, which you can react to, then do the post to the service you're using from your server, and redirect the user to the appropriate URL.
UPDATE
I assume you're using web-forms here.
Issue is that you can post to the URL you want, but your user doesn't see any change on the page. Another issue is that, you're putting your password and API_ID for the service in the post back URL, which is visible to anyone who can navigate to your page and hit F12 key. Making your API_ID available to public is a big mistake. It supposed to be something only you and the remote service should know.
Here's my solution.
When you first load the page, you'll show an empty form and allow the user to enter the data you want.
Then in the click event Handler, you get the data you want and post to the service manually.
A HTTP post contains a list of key-value pairs that you want to send to the service. You have to build the post request manually, and get the response from the remote service.
So here's how your click handler should look like.
protected void btnSMS_Click1(object sender, EventArgs e)
{
Dictionary<string,string> postValues = new Dictionary<string,string>();
// gather the key value pairs ou want from your controls and add them to the dictionary.
// and call postSynchronous method (which I'll explain below)
string result = postSynchronous(URLtoPOST,postValues);
if (result= yourSuccessValue){
// redirect to a page that says.. 'Yay!! you successfully posted to the service ?'
Server.Transfer("successPage.aspx");
}else
{
// what to do if it fails ?
}
}
Now the postSynchronous method (or what ever you want to call it) is something you have to write manually, which will take a RUL to post to and a list of key-value pairs to send with the post, then build the actual post request.
Have a look at this link for a tutorial to learn how to do this.
http://petewarden.typepad.com/searchbrowser/2008/09/how-to-post-an.html
I tried to embed the code for the method and any related methods but it was too long.
So, what's better when doing things this way is that you never send your API keys or passwords down to your user's browser, so they'll never know it. (Otherwise they can use the keys to access the service as you which is a security hole)
What's bad in this, compared your solution is that you're posting on your server, which brings that CPU and network load to your server. But I guess it's good trade off for the security benefits you get.
hope this helps. and feel free to ask any questions.
Is it possible to add the property target="_blank" to the btnSMS item?
If it's a link element it would look like this:
id="btnSMS" href="" target="_blank"
An important tangent --- you are leaving yourself dangerously open to a SQL injection attack.
You should never, never, never concatenate text input from a user with a SQL query.
Use #Parameter values in your SQL query string and then use the SqlCommand parameters to replace those values.
string mySQL = "INSERT INTO Table_Message(Username, Message, Title, SendTo) VALUES(#Username, #Message, #Title, #SendTo)";
SqlCommand cmdAdd = new SqlCommand(mySQL, conn6);
cmdAdd.Parameters.AddWithValue("#Username", username);
cmdAdd.Parameters.AddWithValue("#Message", txtSMS.Text.Trim());
cmdAdd.Parameters.AddWithValue("#Title", txtTitle.Text.Trim());
cmdAdd.Parameters.AddWithValue("#SendTo", txtHP.Text.Trim());
cmdAdd.ExecuteNonQuery();
It would be even better to specify the type explicitly:
cmdAdd.Parameters.Add("#Username", SqlDbType.NVarChar, 100).Value = username;
See Troy Hunt's awesome series - http://www.troyhunt.com/2010/05/owasp-top-10-for-net-developers-part-1.html