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
Related
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;
}
I want user to get the user name and password in the windows form the send it to a web form for the verification, where after verification from the database the entries(which are courses joint by the user) are sent back to the window form, I searched alot but could not get any suitable method, I am new ti c# and asp.net..
I found a way here I am placing my code please tell me is there any better way to do my job.but instead of getting the desired values i get the whole html code so i used to enclose my desired value in html tags on server side which and on client side I am getting the values by using the regular expressions
Here is code for windows from which sends after getting values from the text boxes
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(#"http://localhost:50612/Inclusive_LMS/speech/login.aspx/?stdId=" +tb_stdId.Text + "&pass=" + tb_pass.Text);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
string content = new StreamReader(response.GetResponseStream()).ReadToEnd();
Match valid = Regex.Match(content, #"(?<=(<span[^>]*>))([^<]*)(?=(</span>))");
if (valid.Success)
{
this.Hide();
Student_dashboard ins = new Student_dashboard();
ins.Show();
}
else
{
MessageBox.Show("invalid user Id or password");
}
// textBox2.Text = "" + content + "";
}
catch (Exception ex)
{
MessageBox.Show("check your internet connection, failed to connect the server.");
}
Here is the code for "http://localhost:50612/Inclusive_LMS/speech/login.aspx" page,on designer side I had only one lable on html page
SqlDataReader r;
SqlCommand cmd = new SqlCommand("Select * from Student where Std_Id='" +Convert.ToInt32(Request.QueryString["stdId"]) + "' and Password='" +Request.QueryString["pass"]+ "'", con);
try
{
con.Open();
r = cmd.ExecuteReader();
if (r.Read())
Label1.Text = "success";
else
Label1.Text = "fail";
con.Close();
}
catch
{
Label1.Text = "error";
}
I guess, the best approach would be to access the database directly from the windows application (If it is possible) for any task.
If it is not possible for you to access database directly, you can create a web service in your webform project and consume it in the winforms application. This is easy to implement and works well.
The third approach is to use WebAPI in ASP.NET framework for doing this task.
You need to choose what fits best in your scenario. Best of luck!
Update:
Visit ASP.NET Official Website for lots of resources.
I am trying to create a login page where you would enter in a username and a password. It will query the database for the information you typed in, and if it is in the database, it will log me into the program. If not, it will display a message saying information is not correct.
Here is what I have so far.
private void okButton_Click(object sender, RoutedEventArgs e)
{
try
{
SqlConnection UGIcon = new SqlConnection();
UGIcon.ConnectionString = "XXXXXXXXX; Database=XXXXXXXX; User Id=XXXXXXX; password=XXXXXXXXX";
UGIcon.Open();
SqlCommand cmd = new SqlCommand("SELECT User(Username, '') AS Username, User(Password,'') AS Password, FROM User WHERE Username='"
+ txtUsername.Text + "' and Password='" + txtPassword.Password + "'", UGIcon);
SqlDataReader dr = cmd.ExecuteReader();
string userText = txtUsername.Text;
string passText = txtPassword.Password;
while (dr.Read())
{
if (this.userText(dr["stUsername"].ToString(), userText) &&
this.passText(dr["stPassword"].ToString(), passText))
{
MessageBox.Show("OK");
}
else
{
MessageBox.Show("Error");
}
}
dr.Close();
UGIcon.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
But, the only problem is it does not work at all. I am not sure I have the correct statements to query the database either. I am also getting an error on the "this.userText" As well.
{
if (this.userText(dr["stUsername"].ToString(), userText) &&
this.passText(dr["stPassword"].ToString(), passText))
{
For the error I'm getting, it tells me the WPF does not contain a definition for it
I am a little unsure of how to fix it and go about it as this is the first time I've had to do this. But I think I have a decent start to it though.
There are a couple of things wrong with this structure:
this.userText(dr["stUsername"].ToString(), userText)
First, userText isn't a function, it's a local variable. So I'm not sure what you're even trying to do by invoking it as a function. Are you just trying to compare the variable? Something like this?:
this.userText.Equals(dr["stUsername"].ToString())
Second, the error is telling you that the object doesn't contain a definition for userText because, well, it doesn't. When you do this:
this.userText
you're specifically looking for a class-level member called userText on the object itself. But your variable is local to the function:
string userText = txtUsername.Text;
So just drop the this reference:
userText.Equals(dr["stUsername"].ToString())
Third, the column reference is incorrect. Note how you define the columns in your SQL query:
SELECT User(Username, '') AS Username, User(Password,'') AS Password ...
The column is called Username, not stUsername:
userText.Equals(dr["Username"].ToString())
Edit: #Blam made a good point in a comment, which demonstrates a logical error in the code. If no results are returned from your query, the while loop will never execute. So no message will be shown. You can check for results with something like HasRows:
if (dr.HasRows)
MessageBox.Show("OK");
else
MessageBox.Show("Error");
This kind of renders the previous things moot, of course. But it's still good to know what the problems were and how to correct them, so I'll leave the answer whole for the sake of completeness regarding the overall question.
A few other notes which are important but not immediately related to your question...
Your code is vulnerable to SQL injection attacks. You'll want to look into using parameterized queries instead of concatenating string values like that. Essentially what this code does is treat user input as executable code on the database, allowing users to write their own code for your application.
Please don't store user passwords in plain text. The importance of this can not be overstated. The original text of a password should never be readable from storage. Instead, store a hash of the password. There's a lot more to read on the subject.
Look into using blocks to dispose of resources when you're done with them.
SqlCommand cmd = new SqlCommand("SELECT count(*) FROM User WHERE Username='"
+ txtUsername.Text + "' and Password='" + txtPassword.Password + "'", UGIcon);
Int32 rowsRet = (Int32)cmd.ExecuteScalar();
if(rowsRet > 0)
{
MessageBox.Show("OK");
}
else
{
MessageBox.Show("Error");
}
You still have exposure to SQL injection attack.
I am trying to create a login page. I have a database table called Login, and it has two columns: ID and Password. It has the following ID and Password pairs in it: First row:(13282,123456), Second Row:(11111,11111). If username and password is right, i redirect page to succesful.aspx, if either username or password is wrong, i redirect page to unsuccesful.aspx. My problem is, When i enter 13283 as ID and 123456 as password, it does everything right, i am redirected to succesful page. But when i enter ID=11111 and Password=11111 even though everything is true, it redirects to unsuccesful page. I think the problem is, my query only checks the first row. Here is the code:
protected void loginButton_Click(object sender, EventArgs e)
{
SqlConnection con = new SqlConnection();
con.ConnectionString = "Data Source=.\\SQLEXPRESS;Initial Catalog=University;Integrated Security=True;Pooling=False";
Int32 verify;
string query1 = "Select count(*) from Login where ID='" + idBox.Text + "' and Password='" + passwordBox.Text + "' ";
SqlCommand cmd1 = new SqlCommand(query1, con);
con.Open();
verify = Convert.ToInt32(cmd1.ExecuteScalar());
con.Close();
if (verify > 0)
{
Response.Redirect("succesful.aspx");
}
else
{
Response.Redirect("unsuccesful.aspx",true);
}
}
Several things are wrong with this approach:
It requires storing passwords in plain text - This is the worst thing one can do to a user's password: anyone who accidentally gains access to your database would instantly be in possession of all your users' passwords, with is very, very bad.
It is susceptible to SQL Injection attacks - Concatenating strings to produce a SQL command is dangerous, because malicious users could enter strings that break your SQL and turn it into something else.
You should study the answers to this question. The approaches discussed there are not nearly as simple as what you are implementing, but they make your system a lot more bullet-proof.
I have an ASP.NET c# web application published to a server of ours. It consists of three pages, each with a form on them, sort of like a 3-page login. After the third page's form is validated, it sends the user to a different site. Here's a little diagram so I can explain it better:
NamePage ---> DateOfBirthPage ---> IDNumberPage ---> OtherSite
This has been working great in all of our development tests and stress tests. However, after we put it into production, occasionally when the "Next" button on the IDNumberPage is clicked, the user sees "This page cannot be displayed" with a "diagnose connection problems" button. When this occurs for one user, the same problem occurs for all users (meaning once it happens, nobody can fully authenticate). NamePage and DateOfBirthPage always work, and when the crash occurs, the IDNumberPage link doesn't change, suggesting that the crash is occurring on this side of the application, not after it redirects to OtherSite. I have friendly HTTP errors turned off but it's not showing any errors on the page. If we go into the server and restart the application, it works again.
The frustrating part is that we can't replicate this error to see how/why it's occurring.
Some things that are noteworthy:
Each page uses one query on a MS SQL server database
Each page passes up to 4 Session variables (only small Strings containing what was entered into the textbox form on the previous page(s))
The session is abandoned when the final "next" button is clicked.
All resultsets/connections/commands are closed before redirect.
Redirects use the overloaded version using Response.Redirect(siteName, false)
Sorry if all of this is very vague, but the problem itself has done an oddly good job of hiding from us. We have tried hammering the server with test requests (many at once, many over a period of time, etc) and different combinations of logging in/trying to break the page in general, to no avail. Can anyone suggest some things to try to diagnose/fix/replicate this problem?
Edit: The click function on IDNumberPage's code-behind that is causing the problem:
{ SqlConnection dbconn = new SqlConnection(Application["dbconn"].ToString());
SqlCommand sqlValidate = dbconn.CreateCommand();
dbconn.Open();
sqlValidate.CommandText = "SELECT lastName, csn FROM Demographics WHERE lastName = '" + Session["lastName"].ToString() + "' " +
"AND dob = '" + Session["dobCheck"].ToString() + "' AND mrn = " + strMRN;
SqlDataReader results = sqlValidate.ExecuteReader();
if (results.HasRows)
{
string csn = "";
while (results.Read())
{
if (!String.IsNullOrEmpty(results["csn"].ToString()))
{
csn = results["csn"].ToString();
break;
}
}
string url = Application["surveyUrlString"] + "&lastname=" + Session["lastName"].ToString() + "&mrn=" + strMRN + "&dobday=" + Session["dobday"].ToString()
+ "&dobmonth=" + Session["dobmonth"].ToString() + "&dobyear=" + Session["dobyear"].ToString() + "&csn=" + csn;
results.Close();
dbconn.Close();
Response.Redirect(url, false);
}
The problem is due to leaking sql connections.
You aren't properly disposing of your resources. Over time these are going to stack up in the connection pool until you reach a point where the pool overflows and your app dies. Resetting will obviously fix the issue.
Also this issue might not show up in "stress" tests depending on how, exactly you are testing the application.
The solution is to reformat that code to handle your database call better.
{
string url = string.empty;
using (SqlConnection dbconn = new SqlConnection(Application["dbconn"].ToString())) {
using (SqlCommand sqlValidate = dbconn.CreateCommand()) {
dbconn.Open();
sqlValidate.CommandText = "SELECT lastName, csn FROM Demographics WHERE lastName = '" + Session["lastName"].ToString() + "' " +
"AND dob = '" + Session["dobCheck"].ToString() + "' AND mrn = " + strMRN;
using (SqlDataReader results = sqlValidate.ExecuteReader()) {
if (results.HasRows) {
string csn = "";
while (results.Read())
{
if (!String.IsNullOrEmpty(results["csn"].ToString()))
{
csn = results["csn"].ToString();
break;
}
}
url = Application["surveyUrlString"] + "&lastname=" + Session["lastName"].ToString() + "&mrn=" + strMRN + "&dobday=" + Session["dobday"].ToString()
+ "&dobmonth=" + Session["dobmonth"].ToString() + "&dobyear=" + Session["dobyear"].ToString() + "&csn=" + csn;
}
} // sqldatareader
} // using sqlcommand
} // using sqlconnection
if (!String.IsNullOrEmpty(url)) {
Response.Redirect(url, false);
}
}
notice that you aren't redirecting until after everything is cleaned up.
SqlConnection, SqlCommand and SqlDataReader all implement IDisposable. You have to properly clean up after use otherwise the resources will be left hanging. The "best" way of doing this is to wrap them in a using clause. This ensures they are properly removed once the code block is exited as they aren't garbage collected like other objects.
Also note that the above code has a good side benefit. Namely, in case of error it STILL cleans up after you. Whereas the original code that was posted would clearly leak in the event the DB server didn't respond or threw some type of error when running the query.
The query could error out depending on the values contained in dboCheck, lastname and mrn parameters. For example, what if "BOB" was passed in for the dobCheck field, or Nothing was passed in for mrn... If dob is a datetime field in your database then the query will throw an error that will result in a leaked connection. Do that enough times and your site is down.
Upon further review, I'm guessing that's probably what is happening: people are putting in garbage data that your app is allowing to get to this point and the query is failing. Most likely this isn't something that you've handled in your test cases.
Side note: Please don't create your sql statements by using concatentation. That is a complete security no no. At the very least, parameterize those queries.
Nice answer Chris, one question aren't the .Close() statements missing in the Using statements?. Both for the connection and the datareader:
results.Close();
} // using sqldatareader
} // using sqlcommand
dbconn.Close();
} // using sqlconnection