Monday, July 23, 2007

Creating a PagerTemplate for the GridView Control

When you retrieve a lot of data from a datasource that will be displayed on the page by using the GridView control, you probably don't want to show every row on a single page, especially not when you have hundreds of rows. Displaying hundreds of rows on a single page will use a lot of resources, both on the server and the client. Every row rendered by the GridView contains a set of rendered HTML elements; those will be sent over the network to the browser. If you have several rows that should be displayed, more data will be sent to the client and more bandwidth is required. To minimize the numbers of rows to be displayed on a page, you can use the GridView's paging feature, which will display rows in pages. You can specify how many rows one page will display, and to switch pages you can click a Next button or the number of the page to switch to. Using paging minimizes the data sent over the network and makes it easier for the user to navigate the data. To enable paging, you set the GridView's AllowPaging property to true. When this is done, an additional row called the pager row is automatically displayed in the GridView control. The pager row can be located at the top or the bottom of the GridView control, or both at the top and the bottom of the GridView control. To specify the number of rows that should be displayed on each page, you can use the GridView's PageSize property; by default the value is set to 10, which means that 10 rows will be displayed on each page.

By using the PagerSettings property of the GridView, you can specify how a user switches to another page. You can, for example, specify that you want to use a Preview and Next button, First and Last buttons, and a numeric list, with the number of each page. The user can click the number to move to a specific page. The GridView control only supports a way to specify how the paging row of the GridView should look. You can, for example, use a drop-down list with the number of pages the users can switch to, or use the Previous and Next buttons together with a numeric list. (The GridView doesn't support this currently.) You can create your own pager template to specify exactly how you want the user to switch to another page. To specify your own paging template, you can use the PagerTemplate of the GridView control. The following example uses the PagerTemplate of the GridView to display the selected page and the number of total pages. It also displays Next and Preview buttons for moving between pages:

AllowPaging="True"
Id="GridView1"
...>

Selected Index <%= GridView1.PageIndex * GridView1.PageSize %>
Number of pages <%=GridView1.PageCount %>
CommandName="Page"
CommandArgument="Prev"

Text="Preview" ...>
CommandName="Page"
CommandArgument="Next"
Text="Next" ..>



The whole code example in which the PagerTemplate is used can be found in the file pager1.aspx of the examples files for this chapter, which can be downloaded from http://www.wrox.com.

By using a server-side code block within the template, you can create your own pager. If you want to add a First/Last or Next/Prev button, you simply add a Button control and set its CommandName to Page and the CommandArgument to First, Last, Next, or Prev. You don't need to add any event to handle the paging; the GridView gets the CommandArgument for the buttons you have selected and does the action for you automatically. To add numeric paging, you add Button controls with the CommandName set to Page and the CommandArgument set to the index of the page to navigate to.

You can also programmatically manipulate the top or bottom paging row by using the TopPagerRow or BottomPagerRow property of the GridView control. As you probably have guessed based on the name, the TopPagerRow accesses the pager row located at the top (if you specify rendering the paging control at the top of the GridView) and the BottomPagerRow is the paging control located at the bottom of the GridView. The TopPagerRow and BottomPagerRow are of type GridViewRow. The important thing to remember when you decide to manipulate TopPagerRow or BottomPagerRow is that the manipulation must be performed after the GridView control has been rendered. If you do it before, the changes will be overwritten by the GridView control. A good place to manipulate the pager row is to hook up to the GridView's DataBound event. Listing 7-2 uses the PagerTemplate where a DropDownList control is added, and where the DropDownList control's items represent each page to which a user can navigate. BottomPagerRow is used to manipulate the pager row.

Listing 7-2: Using PagerTemplate with a DropDownList control


<%@ Page language="C#" %>







datasourceid="CustomersSqlDataSource"
ondatabound="CustomersGridView_DataBound"
autogeneratecolumns="true"
allowpaging="true"

runat="server"
pageSize=15>














id="ViewPageLabel"
text="View page:"
runat="server"/>

autopostback="true"
onselectedindexchanged="PageDropDownList_SelectedIndexChanged"
runat="server"/>









id="CustomersSqlDataSource"
connectionstring="<%$ ConnectionStrings:NorthWindConnectionString%>"
selectcommand="Select [CustomerID], [CompanyName], [Address], [City],
[PostalCode], [Country] From [Customers]"
runat="server">









The source code to this example can found in the file pager2.aspx.

The example here uses the Northwind database to get a list of customers from the Customers table.

Let's split the code into pieces and take a look at it in more detail. The example uses a pagerTemplate to specify a custom pager row for the GridView. The pagerTemplate has a table with two columns; the first column has a DropDownList control with the id PageDropDownList. This is where the number of pages a user can select will be added. The other column represents information about which page a user has selected.













id="ViewPageLabel"
text="View page:"
runat="server"/>

id="PageDropDownList"
autopostback="true"
onselectedindexchanged="PageDropDownList_SelectedIndexChanged"
runat="server"/>








PagerDropDownList has the AutoPostBack attribute set to true, and when a user selects a page to view, the PageDropDownList_SelectedIndexChanged event is triggered.

void PageDropDownList_SelectedIndexChanged(Object sender, EventArgs e)
{
GridViewRow bottomPagerRow = CustomersGridView.BottomPagerRow;

DropDownList pageList =
bottomPagerRow.Cells[0].FindControl("PageDropDownList") as DropDownList;

if (pageList != null)
CustomersGridView.PageIndex = pageList.SelectedIndex;
}

PageDropDownList_SelectedIndexChanged uses the BottomPagerRow property of the GridView (CustomerGridView) control to get the GridViewRow that represents the content of the pagerTemplate. To get the PageDropDownList from pagerTemplate, the FindControl method is used. If the PageDrop DownList is found within the GridViewRow cells, the GridView's PageIndex property will be set to the selected index of the PageDropDownList. The index of the selected items in the DropDownList represents the index of the page to be displayed. The PageIndex property of the GridView is used to specify which page a user will see.

Because the manipulation of the pager row must be done after the GridView is rendered, the GridView's DataBound event is used to manipulate the pager row. If the manipulation takes place before the Grid View is rendered, the GridView will reset the manipulation. The DataBound event is triggered after the data is bound to the DataGrid:


id="CustomersGridView"
ondatabound="CustomersGridView_DataBound"
...>

The CustomersGridView_DataBound method is triggered when the GridView's DataBound event is triggered:

void CustomersGridView_DataBound(Object sender, EventArgs e)
{
// Retrieve the pager row.
GridViewRow pagerRow = CustomersGridView.BottomPagerRow;

// Retrieve the DropDownList and Label controls from the row.
DropDownList pageList = pagerRow.Cells[0].FindControl("PageDropDownList")
as DropDownList;

Label pageLabel = pagerRow.Cells[0].FindControl("SelectedPageLabel") as
Label;

The CustomerGridView_DataBound method will get the GridViewRow that represents the pager row from the GridView by using the GridView's BottomPagerRow. In this method, the pages that a user can select will be added to the PageDropDownList inside the GridView's pagerTemplate. FindControl is used to get the PageDropDownList from the BottomPagerRow. There is also a Label control—SelectedPage Label—added to the pager row which represents the current page that is selected.

To get the number of pages in which the datasource is split, you can use the PageCount property of the GridView:

if(pageList != null)
{
//Add the number of pages to the ListBox
for (int i=0; i {
int pageNumber = i + 1;

//Create a ListItem that represents a page
ListItem item = new ListItem(pageNumber.ToString());

To fill the DropDownList in the pager row with the pages a user can navigate to, a for loop is used. The for loop starts from zero and goes to the number of pages into which the data is split. Because the text of the items in the DropDownList should start from one and not from zero, 1 is added to the current index of the for loop and put into a new variable that represents the text the ListItem in the DropDownList will have. A new ListItem is created to be added to the DropDownList later in the code.

When a user selects a page to view from the drop-down list, the current page item in the drop-down list should be selected. That can be done by getting the current index the GridView is displaying by using the PageIndex property of the GridView control:

//If a page is already selected, make sure the
//ListBox selects the selected page
if (i==CustomersGridView.PageIndex)
item.Selected = true;

// Add the ListItem object to the Items collection of the
// DropDownList.
pageList.Items.Add(item);

If the current index of the for loop (used to add an item to DropDownList) is equal to the GridView's PageIndex, the current created item has its Selected property set to true. The Selected property of the ListItem is a marker to tell the DropDownList which item should be selected by default.

The last thing the code example in this topic does is set the Label control inside the pager row to display which page a user has selected, and the number of total pages from which a user can select:

// Get the current page number.
int currentPage = CustomersGridView.PageIndex + 1;

pageLabel.Text = "Page " + currentPage.ToString() +
" of " + CustomersGridView.PageCount.ToString();

To get the total number of pages into which the data returned from the datasource is split, you use the PageCount property of the GridView.

In this section, you learned how to use the pagerTemplate of the GridView control to create and define your own template for the GridView's pager feature. You also learned how to use the BottomPagerRow to manipulate the pager row dynamically with code, and that the manipulation of the pager row must be done after the GridView is rendered.

Saturday, July 21, 2007

Validating a Strong Password in Login Controls

When using both the Create User Wizard and the Change Password controls, users are allowed to enter any password they want. This opens new security holes because too many users enter passwords that are common words. These passwords are easy for the user to remember, but they are also easy for a hacker to figure out. Because the Login controls don't check for weak password vulnerabilities, your site is at risk.
The hack in this section adds validation capabilities to passwords. We're simply going to add a RegularExpressionValidator control. To get started, perform the following actions:
Add a Create User Wizard to a Web form.
Drag a Regular Expression Validator to the right side of the same table cell as the Password TextBox.
Change the RegularExpressionValidator ErrorMessage property to "Must have at least 1 number, 1 special character, and more than 6 characters."
Change the RegularExpressionValidator Text property to *.
Change the RegularExpressionValidator ControlToValidate property to Password.
Change the RegularExpressionValidator ValidationExpression property to "(?=∘.{6,}$)(?=.*\d)(?=.*\W+)(?![.\n]).*$".
Important
As its name suggests, a RegularExpressionValidator control uses what is called a regular expression to perform its validation. Regular expressions are a pattern matching language, which at first glance look cryptic and terse. However, once you know how to use them, you are very likely to find them fast and powerful. A good regular expressions site on the Web is http://regexlib.com.
The HTML for the cell where the Password is located should now look like this:

TextMode="Password">
ControlToValidate="Password"
ErrorMessage="Password is required."
ToolTip="Password is required."
ValidationGroup="CreateUserWizard1">*

ControlToValidate="Password"
ErrorMessage="Must have at least 1 number, 1 special character, and more
than 6 characters."
ValidationExpression=
"(?=^.{6,}$)(?=.*\d)(?=.*\W+)(?![.\n]).*$">*


You can cut and paste the highlighted RegularExpressionValidator element from the preceding HTML into the Password cell of your own templated Create User Wizard. While you're at it, you can add a RegularExpressionValidator control to the Create User Wizard e-mail address, too. The RegularExpressionValidator ValidationExpression property already has a pop-up dialog in which a regular expression for e-mail is available for selection from a list of other regular expressions.
The same technique works for the Change Password control. After adding the Change Password control to your page, select Create Template, and use the same RegularExpressionValidator described above. The only difference will be that you should set the ControlToValidate property to NewPassword

Using Dynamic Impersonation Safely

Impersonation refers to the capability of code to run with the identity of a specific user. Typically, this is the logged on user, but it can also be a designated user (see the userName and password attributes of the identity element in web.config). You would use impersonation so that a user can access a Windows operating system resource with specific permissions. This could be a file on the file system. This is one way to access that resource that would be impossible to access otherwise. Alternatively, you could expand the permissions on the resource, but that may not be good for security.
The identity element in web.config enables you to perform impersonation. When it is turned on, the application runs with the credentials of the currently logged on user. This setting applies to all files in the same directory as the web.config file. Because you don't want every logged on user to have access to protected resources, it is common to put the page that accesses the resource in a separate directory and add a web.config to that directory with impersonation turned on. Then configure security so only a certain user or role can access anything in that directory. After accessing a page in the subdirectory where impersonation is enabled, the user will run with impersonation and be able to access the resource.
When setting the identity element in web.config, a security hazard could exist whereby we can turn on impersonation for all files within the scope of that web.config file. This is convenient, as are many other things in ASP.NET. However, if you are following the security principle of least privilege, it may not be the most secure solution. In fact, it may open a security hole either now or in the future when more pages are added or when maintaining the site. Because the logged on user is impersonating during the entire time they have access to any pages in the same directory, they also have access to everything else to which the impersonated user has access. The most secure solution is to allow access to a resource for only the briefest amount of time possible and only when necessary.
I'm not advocating that you not use impersonation through web.config because if you need it you should use it. Conversely, if you want to restrict access to resources to only those who need it and only when they need it, then dynamic impersonation could be a good choice for you. Listing 14-8 shows how to do this.
Listing 14-8: Dynamic impersonation in code
protected void btnViewGrades_Click(object sender, EventArgs e)
{
Response.Write(WindowsIdentity.GetCurrent().Name + "
");
// impersonate current user
WindowsImpersonationContext ctx =
((WindowsIdentity)User.Identity).Impersonate();
Response.Write(WindowsIdentity.GetCurrent().Name + "
");
try
{
DataSet ds = new DataSet();
// throws exception when user doesn't
ds.ReadXml(Server.MapPath("Grades.xml"));
GridView1.DataSource = ds.Tables[0];
GridView1.DataBind();
}
catch (UnauthorizedAccessException)
{
lblResult.Text = "Not Authorized!";
}
// turn impersonation off
ctx.Undo();
Response.Write(WindowsIdentity.GetCurrent().Name + "
");
}
Calling the Impersonate method of the current user's WindowsIdentity makes the program run with the permissions of the current user. The impersonation context is closed when calling Undo on the WindowsImpersonationContext object that was returned by the call to Impersonate. Therefore, all code between the call to Impersonate and the call to Undo in Listing 14-8 runs with the permissions of the caller. All code outside these bounds runs as the NETWORK SERVICE account (on Windows Server 2003) or the ASPNET account (all other OSs).
Listing 14-8 puts access to a file named Grades.xml within the block of code where we are impersonating. To demonstrate how this works, set ACLs to deny access to this file to everyone but a single person. Then log on with an account that doesn't have access to demonstrate that an UnauthorizedAccess Exception will be raised when you run the program. You can also prove that it works by logging on as the person who does have access and then running the program. Dynamic impersonation allows you to follow the principle of least privilege by limiting impersonation to a single block of code, only when necessary

Using the New File Upload Control

ASP.NET 2.0 includes a new File Upload Web Server control. It works like the HTML File Upload control does except it is object-oriented with Web control properties and you no longer have to manually set the enctype attribute on the form element. What is more significant in terms of security is that you now have a FileName property on the ASP.NET File Upload control. The ASP.NET File Upload control still has the PostedFile property, but you don't need to use it for obtaining the filename anymore. Because the FileName property returns only the filename, and not the full path, there is less opportunity for mishandling the file and opening any security holes:
// the only way to get a file name from an HTML control
string htmlFilePath = fupHtmlUpload.PostedFile.FileName;
// still supported in ASP.NET Web control
string aspNetFilePath = fupAspNetUpload.PostedFile.FileName;
// new FileName property in ASP.NET Web control
string filePath = fupAspNetUpload.FileName;
// use it like this
string fileName = Path.Combine(Server.MapPath("."), filePath);
fupAspNetUpload.SaveAs(fileName);
This discussion assumes that you have weighed the benefits of allowing file uploads and have determined that it is a requirement. Remember that allowing file uploads is another vector that attackers can use to cause Denial-of-Service attacks on your site. You still need to be careful about file permissions you give the ASP .NET user. For example, if you are saving to a directory with a configuration file, the user could upload a file named web.config and overwrite yours. To stop this, put a deny write on the web.config ACL for the ASP.NET user (or the NETWORK SECURITY user on Windows Server 2003). For a more thorough security review, examine the identity that a user is operating to ensure secure settings.

Protecting against Canonicalization Attacks

A canonicalization attack occurs when someone enters a filename requesting a file they aren't allowed to have or overwrites a file they shouldn't. Returning files that a user shouldn't have opens security holes because the file can contain sensitive information you don't want to expose. Allowing users to overwrite files causes a couple of problems. Perhaps they delete important information necessary for the operation of the site or the business. Another problem occurs when someone overwrites a file that is executable with a malicious file that can launch a virus.
The operating system tries to be user friendly and can resolve a filename, regardless of how you specify it. For example, the following four lines are equivalent: type c:\log.txt
type \log.txt
type \..\log.txt
type c:\log.txt;;;
It is difficult to test for every case. Figure 14-3 shows a fictitious example of input that renames a file. Notice that the New Name field is set to C:\\SomeData.xml, which should never be allowed. Sure enough, it is possible to write code that is not secure enough to prevent this. Listing 14-6 shows what happens when you click the Bad Rename button.
Figure 14-3
Listing 14-6: The wrong way to handle filename input

protected void btnBadRename_Click(object sender, EventArgs e)
{
// bad file handling - open to attack
string appPath = Request.PhysicalApplicationPath;
string oldPath = Path.Combine(appPath, txtOldName.Text);
string newPath = Path.Combine(appPath, txtNewName.Text);
File.Move(oldPath, newPath);
}
The problem with Listing 14-6 is that it grabs the input filename with no processing at all. The File class has no knowledge that it is an ASP.NET environment and you get no protection at all. Therefore, it does exactly as told and you'll have to hope that other security mechanisms, such as ACLs, help you out.
To work with filenames, most people use the Request.MapPath or Server.MapPath calls. Besides being a convenient way to get a full path to a file, the MapPath methods also help protect against canonicalization attacks. Listing 14-7 shows the secure way to work with filename input.
Listing 14-7: The proper way to handle filename input
protected void btnGoodRename_Click(object sender, EventArgs e)
{
// good file handling - Server.MapPath
// keeps files in application directory
string oldPath = Server.MapPath(txtOldName.Text);
string newPath = Server.MapPath(txtNewName.Text);
File.Move(oldPath, newPath);
}
I know that most people use the MapPath methods all the time. However, some people just like to be dif- ferent. Also, if you are calling a reusable library that handles files, it may not have security in mind. You should test the library with bad input to determine whether it is secure. If not, you can write your own routine or wrap the call in your own type that does proper validation on the input. Using Request.MapPath and Server.MapPath makes your ASP.NET application more resistant to canonicalization attacks.
Important
If you're wrapping a third-party library to validate input with your own class, you won't have direct access to the Server property. However, you can still get to the MapPath method by calling HttpContext.Current.Server.MapPath();.

Parameterizing an IN Expression

The last section discussed using parameters to secure your code with ad hoc queries. That works fine when you are doing a comparison in a where clause. However, it doesn't work at all if you want to pass a parameter to an IN expression. For example, the following does not work: select EmployeeID, LastName from Employees
where EmployeeID in (@list)
One way to get around this limitation is to use a SQL function. An IN will accept a table. Therefore, you can call a function that parses each element in a comma-separated list, passed in the parameter, and build a table. The function's return value would be the table, which works fine with the IN. Listing 14-4 shows a function that accomplishes this.
Listing 14-4: A function that accepts a parameter and returns a table

SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS OFF
GO
ALTER FUNCTION dbo.ufStringToIntTable (@list varchar(8000))
RETURNS @tbl TABLE (val int,seqnum int) AS
BEGIN
DECLARE @ix int,
@pos int,
@seq int,
@str varchar(8000),
@num int
SET @pos = 1
SET @ix = 1
SET @seq = 1
WHILE @ix > 0
BEGIN
-- extract next parameter
SET @ix = charindex(',', @list, @pos)
IF @ix > 0
SET @str = substring(@list, @pos, @ix - @pos)
ELSE
SET @str = substring(@list, @pos, len(@list))
SET @str = ltrim(rtrim(@str))
-- ensure valid number
IF @str LIKE '%[0-9]%' AND
(@str NOT LIKE '%[^0-9]%' OR
@str LIKE '[-+]%' AND
substring(@str, 2, len(@str)) NOT LIKE '[-+]%[^0-9]%')
BEGIN
-- convert and add number to table
SET @num = convert(int, @str)
INSERT @tbl (val,seqnum) VALUES(@num, @seq)
END
-- prepare for next parameter
SET @pos = @ix + 1
SET @seq = @Seq + 1
END
-- return table with all parameters
RETURN
END
GO
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO
The function in Listing 14-4 accepts a parameter and returns a table. The content of the input parameter is a comma-separated list of numbers. The function parses the values, converts each value to an integer, and adds each integer as a row into the table. This dynamically created table is then returned to the caller. Because an IN expression accepts a table, this works out well. Listing 14-5 shows how this function can be used to accept a parameter for an IN expression.
Listing 14-5: Using a function for an IN Expression









View Employees





















">SelectCommand="SELECT [EmployeeID], [LastName], [FirstName], [Photo]
FROM [Employees] WHERE ([EmployeeID] IN (select val from
ufStringToIntTable(@EmployeeID)))">








Listing 14-5 uses a SqlDataSource control to populate a GridView control. Notice the IN expression in the SelectCommand attribute. It contains …WHERE ([EmployeeID] IN (select val from ufString ToIntTable(@EmployeeID))). ufStringToIntTable is the function from Listing 14-4. As shown in the SelectParameters element, the @EmployeeID parameter is populated from the txtEmployeeIDs TextBox control. You can test this by running the Web form in Listing 14-5 and adding a comma-separated string of numbers. The Northwind Employees table contains nine records, so you can select some, none, or all of them. Pressing the Update button causes a postback that repopulates the GridView control.


Avoiding SQL Injection

One of the more serious threats you'll encounter when exposing a Web application on the Internet is the SQL injection attack. A hacker launches this type of attack by adding extra information to an input field. Your code then interprets this extra input as part of the SQL that it sends to the database.
For example, Figure 14-1 shows an input form in which a hacker is attempting an attack by inserting the following string: ', ''); drop table MyTable;--
Figure 14-1
The hacker is hoping that the code does something insecure, such as concatenate the input with the SQL statement to build the SQL string on the fly. In many situations, this is exactly what is happening in the code, and this section provides some advice about how to avoid it.
Important
With SQL injection, it isn't too hard for attackers to quickly extract data and then figure out your entire database schema. To see how they do it, visit your favorite search engine, starting with the keywords "SQL injection."
In Figure 14-1, the example has two buttons, Bad Add Shipper and Good Add Shipper. The hacker hopes the code like that shown in Listing 14-1 executes when he or she submits the page. The Bad Add Shipper button will run the code in Listing 14-1.
Listing 14-1: The wrong way to build an ad hoc SQL query
protected void btnBadAddShipper_Click(object sender, EventArgs e)
{
string connStr = "Server=(local);Database=Northwind;Integrated
Security=SSPI";
// this is *bad* because the user can
// enter anything they want
string cmdStr =
"insert into Shippers (CompanyName, Phone) values ('" +
txtCompanyName.Text + "', '" + txtPhone.Text + "')";
using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmd = new SqlCommand(cmdStr, conn))
{
conn.Open();
cmd.ExecuteNonQuery();
}
}
The code in Listing 14-1 is bad is because it concatenates the input with the rest of the SQL statement. This causes the resulting SQL command to be sent to the database as follows:
insert into Shippers (CompanyName, Phone) values ('', ''); drop table MyTable;--',
'')
The first part of this statement adds a new row with blank values to the Shippers table. The second part, after the first semicolon (;), removes the MyTable table from the database. The rest of the statement, after the second semicolon, is commented out to prevent errors.
As you can see, attackers can do a lot of damage to your system or view information they aren't supposed to see. Even worse, although it may not be totally obvious by this example, through SQL injection an attacker could potentially take over your entire system.
To fix this problem, you need to use parameters, as shown in Listing 14-2. When the user clicks the Good Add Shipper button, shown in Figure 14-1, it runs the btnGoodAddShipper method, shown in Listing 14-2.
Listing 14-2: The proper way to build an ad hoc SQL query
protected void btnGoodAddShipper_Click(object sender, EventArgs e)
{
string connStr = "Server=(local);Database=Northwind;Integrated
Security=SSPI";
// this is good because all input becomes a
// parameter and not part of the SQL statement
string cmdStr =
"insert into Shippers (CompanyName, Phone) values (" +
"@CompanyName, @Phone)";
using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmd = new SqlCommand(cmdStr, conn))
{
// add parameters
cmd.Parameters.AddWithValue("@CompanyName", txtCompanyName.Text);
cmd.Parameters.AddWithValue("@Phone", txtPhone.Text);
conn.Open();
cmd.ExecuteNonQuery();
}
}
The code in Listing 14-2 is more secure because all input is treated as a parameter, rather than part of the SQL statement. Refer to the documentation on SqlParameter, or the corresponding type for whatever data provider you're using, for information on how to use parameters. An even more secure example would have instantiated a SqlParameter and explicitly set type, size, and other arguments to constrain the input.
ASP.NET v2.0 includes new datasource controls that enable you to add a bindable object to your Web form for populating data controls, such as GridView. These datasource controls accept parameters, meaning that they are also a safe way to get input from the user. For more information, see Chapter 8, "Extreme Data Binding."
Important
In addition to increasing performance, stored procedures are more secure because they require passing input as parameters.
To re-create this scenario, add a test table to your database, such as the one shown in Listing 14-3, and add input as shown in Figure 14-1. Clicking the Bad Add Shipper button deletes the table. However, clicking the Good Add Shipper button processes the input properly.
Listing 14-3: Example table for demonstrating a SQL injection attack
create table MyTable
(
TempColumn char(5)
)
Figure 14-2 shows the output in SQL Query Analyzer after running a couple of queries. Row 4 shows the results of running the insecure code from Listing 14-1 (clicking the Bad Add Shipper button). Row 5 shows the results of running the more secure code from Listing 14-2 (clicking the Good Add Shipper button). As you can see by looking at Row 5, processing input via parameters prevents interpretation of the input as part of the SQL statement and saves that input as column data.
Figure 14-2
If you are coding ad hoc SQL statements, using parameters is one of the best techniques you can use to increase the security of your entire application.

Security Hacks

When most people launch a new website, they are optimistic and look forward to successfully meeting the goals they originally envisioned. Unfortunately, in today's world the hopes of individuals and companies can be instantly dashed by someone with malicious intent. The reality is that part of building a website is considering security. The question to be asked is not "if" but "when" your site will be attacked. Everyone must include security as an integral part of Web application requirements if they are to achieve success.
This chapter includes some techniques to use to harden your system a little better. A couple of the hacks address a particularly insidious attack called the SQL injection attack—including the first hack in the following section, "Avoiding SQL Injection." This chapter includes a related hack that enables you to parameterize a SQL IN expression, which is another way to avoid SQL injection. You'll also find a couple of hacks dealing with canonicalization attacks—those involving URIs that try to bypass normal address and filename checking. For those of you who have OS resources, such as files on a system guarded by Windows authentication, this chapter includes an impersonation hack you can use. Last, but not least, there is a hack for extending the ASP.NET Login control to validate a strong password. Certainly, there is much more to cover in the world of security, but it is hoped that the hacks in this chapter give you some important reusable code and techniques and stimulate your own thinking about how to make your applications more secure.

Tuesday, May 22, 2007

ما هي UML

؟ما هي UML ؟
لغة النمذجة الموحّدة (Unified Modelling Language)، أو (UML) ، هي لغة نمذجة رسومية تقدم لنا صيغة لوصف العناصر الرئيسية للنظم البرمجية. (هذه العناصر تسمّى artifacts مشغولات في UML). في هذه الفصول سوف نستكشف النواحي الرئيسية في UML، و نصف كيف يمكن تطبيق UML في مشروعات تطوير البرمجيات.
تتّجه UML بطبيعتها نحو بناء البرمجيات كائنية المنحى object oriented ، لذلك سوف نستكشف بعض أهم مبادئ المنحى الكائني.
في هذا الفصل القصير، سوف نلقي نظرة على أصول UML، و سنناقش الاحتياج إلى لغة مشتركة في صناعة البرمجيات. بعدها نرى كيف يتم تطبيق UML على مشروع برمجي.
لغة مشتركة
الصناعات الأخرى لديها لغات و رموز خاصة بها، و يفهمها كل من له علاقة في حقل اختصاص معين.
شكل 1 ـ معادلة رياضية للتكامل
بالرغم من أن الصورة أعلاه هي رسم بسيط جدا ، فإن الرياضيين في كل العالم يدركون و من أول وهلة بأنها تمثل معادلة تكامل . و بالرغم من بساطة الرمز، إلا أنه يشير إلى موضوع بالغ العمق و التعقيد. الرمز بسيط، و لكن بالمقابل، كل الرياضيين في العالم يمكنهم و بكل وضوح تبادل الآراء فيما بينهم باستخدامه مع مجموعة بسيطة أخرى من الرموز. الرياضيون هنا لديهم لغة مشتركة. كذلك الموسيقيون، و مهندسو الالكترونيات، و الكثير من الفروع والمهن الأخرى.
لمدة، كان مهندسو البرمجيات يفتقرون لمثل هذه الرموز. بين عامي 1989 و 1994، و هي الفترة التي يشار إليها بـ "حروب المناهج"، كان يوجد ما يزيد عن 50 لغة نمذجة برمجية قيد الاستعمال - كل منها تملك رموزها الخاصة! كل لغة تحتوي على قواعد تميزها، بينما في نفس الوقت، كل لغة لديها عناصر تتشابه مع تلك التي في اللغات الأخرى.
و لمزيد من الفوضى، لا توجد لغة متكاملة، بحيث نادرا ما يجد القائمون على البرمجيات ما يرضي كامل حاجتهم في لغة واحدة!
في منتصف التسعينيات، برزت ثلاث منهجيات لكي تكون الأقوى. بدأت هذه المنهجيات الثلاث في التقارب، كل واحدة منها تحوي على عناصر من الأخريين. كل منهجية تملك نقاط قوة خاصة بها:
· بوك Booch كانت ممتازة فيما يخص التصميم و التنفيذ. لقد عمل "قرادي بوك" Grady Booch بكثافة على لغة آدا Ada، و كان له دور رئيسي في تطوير تقنيات المنحى الكائني (object oriented) للغة. وبالرغم من قوة منهجية بوك إلا أن الرموز فيها لم تأخذ القبول الحسن (الكثير من الأشكال السحابية تغزو نماذجه - ليست بالجميلة!)
· OMT (تقنية النمذجة الكائنية Object Modelling Technique) كانت الأفضل في التحليل و في أنظمة المعلومات ذات البيانات الكثيفة.
· OOSE (Object Oriented Software Engineering هندسة البرمجيات كائنية المنحى) و تتميز بنموذج يسمى وقائع الاستخدام (Use Cases). تعد وقائع الاستخدام أسلوب قوي من أجل فهم سلوك كامل النظام (و هو المجال الذي كان فيه المنحى الكائني ضعيفا).
في عام 1994، قام جيم رامبخ Jim Rumbaugh، مؤسس OMT، بمفاجأة عالم البرمجيات حين ترك العمل بشركة جنرال الكتريك General Electric و انضمّ الى قرادي بوك للعمل في شركة راشيونال (Rational Corp). الغرض من المشاركة كانت من أجل دمج أفكارهما و صبّها في منهجية موحدة (و كان بالطبع عنوان العمل لهذه المنهجية هي "المنهجية الموحدة" Unified Method).مع عام 1995، انضم أيضا مبدع OOSE ايفار جاكوبسون Ivar Jacobson، إلى راشيونال، و تم ضم أفكاره (خاصة مفهوم "وقائع الاستخدام" Use Cases) في المنهجية الموحدة - الآن تدعى لغة النمذجة الموحدة (Unified Modelling Language).* وعُرف الفريق الذي يتكون من رامبخ و بوك و جاكوبسون بـ "الأصدقاء الثلاثة" (Three Amigos).
بغض النظر عن بعض الحروب و المشاحنات البسيطة، بدأت المنهجية الجديدة تجد استحبابا لدى أوساط صناعة البرمجيات، فتم تكوين لجنة مشتركة consortium خاصة بـ UML، شاركت فيها عدد من المؤسسات ثقيلة الوزن مثل هيولت-باكارد (Hewlett-Packard) و ميكروسوفت (Microsoft) و أوراكل (Oracle).
كما تم تبنّي UML من قبل منظمة (OMG) ** في 1979، و من حينها امتلكت (OMG) اللغة و دأبت على صيانتها. لذلك عمليا أصبحت لغة UML عامة وليست ملكية خاصة.
ملخص
UML هي لغة رسومية للتعبير عن مشغولات (artifacts) التطوير البرمجي.
تقدم لنا اللغة رموزا ننتج بها النماذج.
تلقى UML تبنيا واسعا في الوسط الصناعي كلغة موحدة.
اللغة غنيّة جدا، و تحمل في طيّاتها العديد من جوانب أفضل الممارسات في هندسة البرمجيات.
* التسمية الرسمية هي modeling، وما ورد هو التهجئة الانكليزية للكلمة.
** OMG: مجموعة الإدارة الكائنية (Object Management Group)، و هي جهة غير ربحية لوضع المواصفات. انظر www.omg.org لمزيد من التفاصيل.

Wednesday, April 25, 2007

  • قريبا بإن الله تعالة سيتم إفتتاح الموقع العلمي الجديد لكل مبرمجي الدوت نت فأنتظرونا علي الموقع الجديد قريبا
  • هناك اشياء تستحق الانتظار
  • قريبا ان شاء الله تعالي افتتاح الموقع الجديد
  • ُEng.eslam.asp.net
قمر في كبد ليليٍ مظلم كان لي رايةفـ بـطلـوع الفجــر أيقنت أن هـناك آيةيمضي الليل تلو الليلوانا في انتظار ظهور القمرالقمر ذاك البدر الذي ينير دربيذاك المخلوق العجيبكوكبٌ زهري , ينير الأرض إذا حل الظلامالقمرمنذ إختفائك عن عينيأعيش بلا حياة أموت بلا انتحار رصاصة تلو رصاصة تخترق جسدي النحيللم أعد أقوى على الحراكولم يذق جفني النومسهرت لياليٍ طِـوال أملاً في لقائكأتعبتني , بعثرتني , قتلتنيالقمرتركت ابتسامه معلقة على شفتيوعيناي قد أسرت بجمالكلقد غرسة المحبه في قلبيأتعلم أيها القمركانت فتاة شرقية , في الجمال آيةسحرتني , أبهرتني , بـعذب كلماتها أسرتيلقد كنتُ لها قبطان , وبحر و ميناء!! , , , ولكن , , , !!عالمنا صغيرلم نلتقي في يوملم يكن هناك محبة ولا فراق بل لم يكن هناك لقاءأحلام و أماني تراكمت وأثكلت كاهليلم أعد بإستطاعتي الصمود طويلاًلقد تجمد الحب في قلبي وتخثر دميولم يعد هناك نبض ولا روح تتجسدنيشاء القـدر أن ترحل فرحلت وتركتني وذهبت
فالموت فرق بيننا ماتت ماتت
في اليل لم اعد اطيق الليل لم استطيع ان انام مثل الناس
في الليل تحولت إلي كائن اخر لا انام
هذا الليل الظالم لا اقدر اتحمل ظلمة سوادة لا اطقه اذهبو بيه عني
رحمكي الله يادرة قلبي وعمري

Saturday, March 17, 2007

يوم في حياة صفحة ASP.NET

كم من صفحة ASP.NET بنيتُها ثم تركتاها ولم أعلم عنها شئ بعد ذلك، ياترى ماذا تفعل الآن وإن طلبها المستخدم أمازلت تلبي النداء أم أن شئ ما في يومها تكدر فلم تعد تجيب النداء وبدلاً من أن أفكر في كل صفحة بعد بنائها قررت أن أعرف كيف تقضي أي صفحة ASP.NET يومها حتى لا أكدره عليها بالخطأ أثناء بنائي إياها وأليكم مذكرات يوم في حياة صفحة ASP.NET



لا تبادر أي صفحة ASP.NET ببدء يومها من نفسها بل يعتمد بداية يومها على طلب المستخدم لها وعلى الرغم من عدم قدرتها على التنبؤ بالوقت الذي ستبدأ فيها يومها – أو قل وقت استيقاظها – إلا إنها تعرف تمام المعرفة الأماكن التي عليها أن تمر عليها كل يوم، واستحييت أن أكون أنا مبرمجها ولست على نفس درايتها بالأماكن التي تمر فيها والغرف التي تقضي فيها وقتها ففضلت البدء بمعرفة الغرف التي تقضي الصفحة فيها وقتها ثم استطلع كل غرفة جيدا ثم بعد ذلك أعطي لها أمر بالاستيقاظ وأراقبها أثناء مرورها على كل هذه الأماكن لأتعرف بالتفصيل على رحلتها اليومية وسأبدأ بسرد ما علمته عن الغرف التي تقضي فيها وقتها وهي كالتي :



1- غرفة ال IIS

> وعزمت في هذه الغرفة إلا أخرج إلا بعد أن أفهم الآتي :

> - نظرة عامة

> - ماذا يحدث تحت الغطاء



أما عن النظرة العامة

فهذه الغرفة هي المكان المختص باستقبال طلبات تشغيل صفحة ويب معينة والمسئول عن خدمة هذه الطلبات هو خادم Internet Information Services (IIS) وهو يعتبر الوسيط الذي لا غنى عنه بين المستخدم وبين موقع الانترنت وذلك لأنه يستطيع التعامل مع المستخدم وطلباته ويعرف كيفية الرد عليه بالأسلوب الذي يفهمه المستخدم وفي نفس الوقت قادر على التعامل مع ملفات موقع الانترنت بما يناسبها ونقل نتيجة تشغيلها إلي المستخدم ، ولا تقتصر خدماته على صفحات ASP.NET فقط بل تمتد إلي Classic ASP و HTML وأي تقنيه تدعم IIS وأولى ملاحظاتي على هذه الغرفة كانت كما يلي :

- لن يتمكن أي طلب لصفحة ويب من المرور إلا عن طريق توجيه طلبه إلي IIS وإلا فلا يمكن خدمته.

- ليس هناك إلا طريق واحد فقط لطلب تشغيل صفحة عن طريق IIS وهو ما يطلق عليه ال HTTP Request يكون محدد فيه عنوان الصفحة المستهدفة بالإضافة إلي معلومات أخرى.

- أي نتيجة تخرج من IIS إلي المستخدم يجب أن تخرج في HTTP Response يحتوى نتيجة طلب المستخدم

- تعمل جميع إصدارات IIS التي تسبق IIS 6.0 تحت اسم inetinfo.exe أما في حالة IIS 6.0 فأنه يعمل تحت اسم w3wp.exe



أما عن ما يجدث تحت الغطاء فكان كالتالي

يستطيع ال IIS تمييز الصفحات عن طريق الامتداد الخاص بها مثل .html .asp .aspx وبالتالي تغيير طريقة تعامله مع الصفحة بما يناسب التقنية المبنية بها، وتغيير طريقة تعامله هي أكثر من مجرد ثلاث كلمات لذا استوقفني قليلاً فقد سألت نفسي أربع أسئلة وهم كالتالي

1- ماذا لو ظهرت لغة جديدة ولتكن XSP لتطوير صفحات ويب فكيف سيغير IIS طريقة تعامله مع الصفحات المبنية بهذه اللغة وهو لم يكن يعرف بها من قبل

2- ما هي الخطوات التي يتبعها IIS لمعالجة طلبات تشغيل الصفحات المختلفة ؟

3- هل يستطيع IIS حجب بعض الصفحات أو الملفات عن المستخدم حتى وإن كانت موجودة عنده ؟ وهل يمكنني أن أضبطه بحيث يحجب ملفات خاص بي لا أرغب في أن يطلع عليها المستخدم ؟

4- كيف سيتصرف IIS إذا تعرف على امتداد صفحة وكان .aspx وعرف أنها ستعمل على ASP.NET وكان هناك نسختين مركبتين منها وهما ASP.NET 1.1 & ASP.NET 2.0



وإجابة السؤال الأول “ماذا لو ظهرت لغة جديدة ” كانت كالتالي

علمت مايكروسوفت أنها لن تستطيع أن توفر كل الدعم المطلوب لجميع لغات البرمجة الموجودة والمستحدثة لذا فقد طورت مايكروسوفت نظام Internet Server Application Programming Interface (ISAPI) Extension وهو نظام يهدف إلي إكساب IIS القدرة على توسعة إمكانياته ، بحيث يمكن لأي مبرمج تطوير ISAPI Extension جديد والحاقة بال IIS بحيث يكسب IIS القدرة على التعامل مع أنواع ملفات جديدة لم يكن ال IIS يعلم عنها شيئاً قبل ذلك، وأوضح الأمثلة العملية على ذلك هي ال ASP.NET نفسها فال.NET Framework أثناء تركيبه يلحق ISAPI Extension خاص بال ASP.NET وهو aspnet_isapi.dll بحيث يكسب ال IIS القدرة على معالجة الصفحات المبنية بتقنية ال .NET ويمكن توضيح الفرق قبل تركيب aspnet_isapi وبعد تركيبه وأثر تركيبه على IIS عن طريق الشكلين التاليين :



————————————————————————————————



لعل وظيفة ISAPI Extension تكون قد اتضحت الآن فهو من أكسب IIS القدرة على التعامل مع ملفات ASP.NET والوافد الجديد علينا في الشكل الثاني هو aspnet_wp وهو عبارة عن المحرك الرئيسي لتشغيل ASP.NET فكل ما يفعله aspnet_isapi بعد استلامه أمر تشغيل صفحة معينة أن يناول هذا الأمر إلي العملية المسماة ASP.NET Worker Process (aspnet_wp ) بحيث تتولى هي كل ما يلزم فعله حتى يتم خدمة هذا الطلب وسنتعرض لها بالتفصيل في المقالة القادمة إن شاء الله لأنها هي الغرفة الثانية التي تدخلها أي صفحة ASP.NET



أما عن “ما هي الخطوات التي يتبعها IIS لمعالجة طلبات تشغيل الصفحات المختلفة ؟” فإجابته كالتالي :

1- عن طريق HTTP Request يحدد IIS امتداد الصفحة المطلوبة سواء كان aspx , asp , html ويحدد أيضاً اسم الموقع الموجود به هذه الصفحة

2- يُعلم IIS جميع ال ISAPI Filters الملحقة به بوصول HTTP Request جديد ويمرر هذا الطلب على جميع المرشحات ISAPI Filters

3- يذهب IIS إلي ScriptMaps خاصة بالموقع المطلوب ويعرف من هذه الخرائط ال ISAPI Extension المناسب لتشغيل هذا الامتداد داخل هذا الموقع

4- يوجه IIS طلباً مباشراً إلي ISAPI Extension المستهدف بتشغيل الصفحة المرادة عن طريق أمر مثل هذا Http://Server_Name/MyISAPIExtension.dll?TargetURL

5- بعد استقبال نتيجة تشغيل الصفحة من ال ISAPI Extension يُعلم IIS جميع ال ISAPI Filters بأن هناك HTTP Response على وشك الإرسال إلي المستخدم ويمرره عليهم جميعاً

6- يرسل IIS نتيجة تشغيل الصفحة في HTTP Response إلي المستخدم





ولعل هناك تساؤل عن كلمتين جديدتين وهما ISAPI Filters و ScriptMaps وكل واحدة من منهما هي إجابة للسؤالين الثالث والرابع ، لذا لنستعرض كل سؤال



فالسؤال الثالث كان “هل يستطيع IIS حجب بعض الصفحات أو الملفات عن المستخدم حتى وإن كانت موجودة عنده ؟ وهل يمكنني أن أضبطه بحيث يحجب ملفات خاص بي لا أرغب في أن يطلع عليها المستخدم ؟”

فإجابة هذا السؤال هي نعم يستطيع IIS حجب ما يشاء من صفحات وملفات عن مستخدم بعينه أو حتى كل المستخدمين وذلك عن طريق ISAPI Filters فكما سبق توضيحه فإن أي HTTP Request & HTTP Response داخل أو خارج يمر على جميع ال HTTP Filters الملحقة ب IIS وإن قرر أحد تلك المرشحات أن يحجب النتيجة عن المستخدم فلن يتم إرسال أي نتيجة إليه ولا يمرر IIS طلب المستخدم دفعة واحدة على كل المرشحات بل يمرر الطلب على مرشح تلو الآخر على حسب الأولوية المسجل بها هذا المرشح وإن تساووا في في الأولوية فأنه يمرر على على حسب ترتيب تسجيل هذا المرشح داخل IIS وإن كان هناك حاجة لحجب محتويات معينة عن المستخدمين يمكن بسهولة أن نطور ISAPI Filter خاص بنا يتولى ترشيح الطلبات قبل وصولها إلي موقعنا ويمكن إضافة وحذف وتعديل ترتيب التسجيل لأي ISAPI Filter عن طريق هذه الشاشة



والتي يمكن الحصول عليها بإتباع المسار التالي

Control Panel > Administrative Tools > Internet Information Services > [Server Name] > Default Websites > Mouse Right Click > Properties > ISAPI Filters Tab

[Server Name] هو اسم الحاسوب المركب عليه IIS

وهذه المرشحات لا تستطيع تشغيل أي صفحة بل كل حدودها في حجب الطلبات أو إعادة كتابة عنوان الصفحة سواء القادم من المستخدم أو المرسل إليه ويمكن التوضيح بالمثالين التاليين

*** عنوان قادم من المستخدم مكتوب فيه HTTP://www.MySite.com/MyPage.aspx/UserName/Ahmed يمكن للمرشحات أن تعيد كتابة العنوان بالشكل التالي

HTTP://www.MySite.com/MyPage.aspx?UserName = Ahmed وبالتالي سيأخذ IIS هذا العنوان الجديد ويناوله إلي ال ISAPI Extension المناسب لمعالجة هذا العنوان



*** المثال الآخر هو في حالة إرسال عنوان صفحة في HTTP Response فالطبيعي أن يكون العنوان المرسل إلي المستخدم كالتالي HTTP://www.MySite.com/YourPage.aspx وقد نحتاج إن لا نعلم المستخدم بالتقنية المستخدمة في تطوير الموقع فيمكننا عن طريق ISAPI Filter أن نعيد كتابة العنوان قبل إرساله إلي المستخدم ليصبح HTTP://www.MySite.com

ويمكن تلخيص وظيفة ISAPI Filters في هذ الشكل




ننتقل الآن لتوضيح ال ScriptMaps وفي نفس الوقت الإجابة على السؤال الرابع والأخير والذي كان “كيف سيتصرف IIS إذا تعرف على امتداد صفحة وكان .aspx وعرف أنها ستعمل على ASP.NET وكان هناك نسختين مركبتين منها وهما ASP.NET 1.1 & ASP.NET “

قبل أن يوجه IIS طلب المستخدم للتشغيل عليه أن يقرأ أولاً ال ScriptMaps الخاصة بالموقع الذي تعمل بداخله الصفحة المرادة لأن كل موقع له ScriptMaps توضح امتدادات الملفات المدعمة من قبله وال ISAPI Extension المناسب لتشغيل كل امتداد لذا فلو كان هناك موقعين يعملان ب ASP.NET ولكن لكل موقع إصدارة مختلفة من إصدارات ال ASP.NET فهذا يعني أن لكل موقع ScriptMaps مختلفة عن الآخر وهذا ما سيمنع تضارب تشغيل الصفحات بين الموقعين وعملية تسجيل هذه البيانات في ال ScriptMaps تسمى Script Mapping أو Application Mapping أيهما صحيح ويمكنك الإطلاع على ScriptsMaps الخاصة بكل موقع عن طريق هذه الشاشة



والتي يمكن الحصول عليها بإتباع المسار التالي

Control Panel > Administrative Tools > Internet Information Services > [Server Name] > Default Websites > [Any Web Site] > Mouse Right Click > Properties > Virtual Directory Tab > Configuration Button



أما عن ماذا يحدث بعد أن يوجه IIS أمر تشغيل مباشر إلي aspnet_isapi Extension وكيف يناوله aspnet_isapi إلي aspnet_wp.exe وماذا يحدث داخل aspnet_wp فهذا ما سنتعرف عليه في المقالة القادمة إن شاء الله “داخل غرفة aspnet_wp”

————————————————————————————————–

ملاحظة : —

على الرغم من الكلام في المقال أنصب على IIS فقط إلا أنه ينطبق على أي خادم ويب يدعم ASP.NET

Wednesday, March 7, 2007

ping server by programing

Form one month i'm design Ads with new technology but it's very heavy so that we separate this Ads in different server to protect our original server ok until now i'm don't have any problem but the problem was appear when mr:president request from me to test server that has Ads befor load from it because if it has problem we load on page different ads so
From two weeks or more I skim force internet to search How to solve this problem
but today i found alot of solution for this problem one with sql server but we don't have permission to do it . but I found the excellent solution with asp classic , C# ,VB i thing with any lang
this is solution with VB .net 2005 :
------------------------------------------------------------------
Public Function END_Ping(ByVal url As String) As Boolean
Dim objWShell As Object
objWShell = CreateObject("WScript.Shell")
Dim objCmd As Object
Dim strPResult As Object
objCmd = objWShell.Exec("ping " & url)
strPResult = objCmd.StdOut.Readall()
objCmd = Nothing : objWShell = Nothing
If InStr(strPResult, "TTL=") > 0 Then
Return True ' in corect
Else
Return False ' in error
End If
End Function

-------------------------------------------------
and this with asp classic

<% url = "www.yahdffdoo.com"
Set objWShell = CreateObject("WScript.Shell")
Set objCmd = objWShell.Exec("ping " & url)
strPResult = objCmd.StdOut.Readall()
set objCmd = nothing: Set objWShell = nothing
if InStr(strPResult,"TTL=")>0 then
Response.Redirect("http://www.googel.com") ' in error
else Response.Redirect("http://www.yahoo.com") ' in corect
end if %>

Thanks Allah for all thing

Sunday, February 11, 2007

من اسير الحزن ؟

ـ جرت العادة بأن يعرف الشخص عن نفسه بطريقة تقليدية وأنا الـيـوم أعـرفكـم على نفسـي من خــلال خـاطـرتـي هذه ..واتمنى أن أوفــق في نـقـل صورة صريحة عن شخصية أسير الحزن ..


أنــــــــــــــــــــــــا
احساس مغرور .. خالى شعوريمشى بين الناس محطم مكسور
أنــــــــــــــــــــــــا
روح ... ميته بروحوجروح ... تنزف جروحوعالمى ... كله مهدوم الصروح
أنــــــــــــــــــــــــا
حرف ... بدفاتر منسيهبعد ماكنت قصيده ... بامسيه شعريه
أنــــــــــــــــــــــــا
أسير خيــالــى مفتاح قيدى .. فى سلاسل أمالىوأمالى .. مفقوده بين وديان هموم جبالى
أنــــــــــــــــــــــــا
لحن غريب .. بمزمار السنينفيه من الحنين .. وفيه من نغمات الانينوفيه كسرات عود .. بلحن حزين
أنـــــــــــــــــــــــــا
إبتهال .. فى يدين حـــــــــــــــايرضاقت به الدنيا ... وثــــــــــــايرماجنا بحياته غير الخســــــــــايريطلب من ربه .. ويرتجيه يستجيب لدعاه .. ويرضيه
أنـــــــــــــــــــــــــا
وجه الربيع .. الشاحب من الظماءعطشان .. والماء رد جفــــــــــــــــــاءخايف .. من برد الشتاءفى نهاره .. والمســـــــــــــــــــــاء
أنــــــــــــــــــــــــــا
ذكرى قديمهمبتور صاحبــــــــــــــــهايقتلها الماضى ويحيهـــــــــــــــــا حاضرها
أنــــــــــــــــــــــــــا
روح ... هنيه فى رحم الدنيا .. الشقيه مكتوب ساعه ولادتى بلحظه من دقايق وفاتى
أنـــــــــــــــــــــــــــا
خيالي .. بدنيا واقعيه احزانى بقلبى .. شاعريهتعجبنى رسمات الحروف الابجديه
أنــــــــــــــــــــــــــــاالنهايه .. فى الفرحوالبدايه .. بالاحزان وانا كل الــجرووح تغنى لى بأعذب اللحان
وأنـــــــــــــــــــــــــــا
نهايـه فى حـــروف خـــاطــرتــى أنـــــا
أســــــــــير الحزن

Friday, February 9, 2007

I have a MCP Microsoft certificate since 2006 And now I'm work at Universal Solutions S.A.E ( WWW.UNIVERSOL.BIZ) since NOV2006

Hi my Frindes

Hi guys :
Ii'm Elam Nader Ibrahem Desokey
Web developer From Egypt