The current version of SilverlightDesktop implements security by assigning a temporary password to the user when they launch the Silverlight application. This password is passed to the Silverlight application through the InitParameter. The SilverlightDesktop application uses this password when communicating with the web services.
Then we had a thought. What if you wanted to guess the passwords on a SilverlightDesktop site? You know the temporary password is always a number. Yes it is a large number, but you could write a program that sat there all day trying one number after another.
To combat this we decided to implement a count of bad password attempts. After a certain amount of attempts the account would be locked. The problem with this is that your could shut down a site by intentionally sending bad passwords and locking out accounts with known user names.
The solution is to store the IP Address as well as the temporary password. Both would be needed to authenticate a user. To launch a brute force attack a hacker would have to know your username and IP address.
However, a hacker could create a SilverlightDesktop module that sent harmless information to their website. They now know the SilverlightDesktop user's account name and password. They can now begin a brute force attack.
We then added code to change the temporary password ONLY if it was incorrect AND the correct IP address was used. A hacker could shut down accounts (temporarily, the accounts will work again after the person logs back in) only if they were able to somehow gather the person's IP address. Without the correct IP address a brute force attack could actually guess the correct password yet still not gain access.
Download the latest source code version for a full example of this. We expect to release a new install version in a week or two.
Here is an outline of we have done:
1) SilverlightDesktop.aspx.cs contains the code that launches the Silverlight control. It uses this code to pass the InitParameters. It now stores the IP address using the Authendication.SetSilverlightKey method:
string strIPAddress = this.Context.Request.UserHostAddress;
int intUserID = GetUserID();
int intPassword = Authendication.SetSilverlightKey(intUserID, strIPAddress);
...
Desktop.InitParameters = String.Format("PortalID={0},ModuleId={1},UserID={2},Password={3},WebServiceBase={4}", "0", "0", intUserID.ToString(), intPassword.ToString(), strWebServiceBase);
2) In the App.xaml.cs file in the SilverlightDesktop project (the Silverlight application that creates the windows that the other Silverlight modules are loaded into), the following code retrieves the parameters and passes them to the application.
private void Application_Startup(object sender, StartupEventArgs e)
{
// Load the main control
this.RootVisual = new Page(e.InitParams["PortalID"], e.InitParams["ModuleId"], e.InitParams["UserID"], e.InitParams["Password"], e.InitParams["WebServiceBase"]);
}
#region SayHelloVisitor
private void SayHelloVisitor()
{
var proxy = new WebServiceSoapClient();
EndpointAddress MyEndpointAddress = new EndpointAddress(strWebServiceBase + "Webservice.asmx");
proxy.Endpoint.Address = MyEndpointAddress;
proxy.HelloUserCompleted += new EventHandler<HelloUserCompletedEventArgs>(proxy_HelloUserCompleted);
proxy.HelloUserAsync(intPortalID, intModuleId, intUserID, strPassword);
}
void proxy_HelloUserCompleted(object sender, HelloUserCompletedEventArgs e)
{
HelloVisitor.Text = e.Result.ToString();
}
#endregion
4) The web service passes this temporary password and the IP address of the Silverlight application calling it to the Authentication class:
#region HelloUser
[WebMethod(Description = "HelloUser")]
[ScriptMethod()]
public string HelloUser(int PortalID, int ModuleId, int UserID, string Password)
{
string strIPAddress = this.Context.Request.UserHostAddress;
SilverlightDesktopAuthendicationHeader SilverlightDesktopAuthendicationHeader = new SilverlightDesktopAuthendicationHeader();
SilverlightDesktopAuthendicationHeader.PortalID = PortalID;
SilverlightDesktopAuthendicationHeader.UserID = UserID;
SilverlightDesktopAuthendicationHeader.Password = Password;
SilverlightDesktopAuthendicationHeader.ModuleId = ModuleId;
SilverlightDesktopAuthendicationHeader.IPAddress = strIPAddress;
string response = "";
Authendication Authendication = new Authendication(SilverlightDesktopAuthendicationHeader);
if (Authendication.IsUserValid())
{
UserInfo objUser = Authendication.GetUserInfo();
response = String.Format("Hello {0}! [{1}]", objUser.DisplayName, strIPAddress);
}
else
{
response = String.Format("Hello SilverlightDesktop Visitor! [{0}]", strIPAddress);
}
return response;
}
#endregion
#region IsUserValid
public bool IsUserValid()
{
if (_UserID == -1)
{
return false;
}
// Get the SilverlightKey
SilverlightDesktopDAL SilverlightDesktopDAL = new SilverlightDesktopDAL();
var result = (from ASilverlightDesktopUser in SilverlightDesktopDAL.SilverlightDesktopUsers
where ASilverlightDesktopUser.UserID == _UserID
select ASilverlightDesktopUser).FirstOrDefault();
if (result.SilverlightKey == ConvertToSilverlightkey(_Password) & result.IPAddress == _IPAddress)
{
return true;
}
else
{
if(result.IPAddress == _IPAddress)
{
// The correct IP address was used
// To prevent a brute force attack scramble the password
// A hacker is now chasing a moving target
SetSilverlightKey();
}
return false;
}
}
private int ConvertToSilverlightkey(string _Password)
{
int SlverlightKey;
if (int.TryParse(_Password, out SlverlightKey) == false)
{
SlverlightKey = 0;
}
return SlverlightKey;
}
#endregion