• IBM Consulting

    DBA Consulting can help you with IBM BI and Web related work. Also IBM Linux is our portfolio.

  • Oracle Consulting

    For Oracle related consulting and Database work and support and Migration call DBA Consulting.

  • Novell/RedHat Consulting

    For all Novell Suse Linux and SAP on Suse Linux questions releated to OS and BI solutions. And offcourse also for the great RedHat products like RedHat Enterprise Server and JBoss middelware and BI on RedHat.

  • Microsoft Consulting

    For Microsoft Server 2012 onwards, Microsoft Client Windows 7 and higher, Microsoft Cloud Services (Azure,Office 365, etc.) related consulting services.

  • Citrix Consulting

    Citrix VDI in a box, Desktop Vertualizations and Citrix Netscaler security.

  • Web Development

    Web Development (Static Websites, CMS Websites (Drupal 7/8, WordPress, Joomla, Responsive Websites and Adaptive Websites).

20 February 2010

Preventing spam when using PHP's mail function
Anyone who has an email address can tell you that spam is one of the great banes of the online world. But it's not only distant servers owned by the spammers that are to blame. It may even be your very own server. Insecure PHP scripts have provided great opportunities for spammers to abuse other's resources to send out their spam. In particular, it's the mail() function that can be abused. I myself was the target a few months ago when I noticed spam being sent from an old form on my server that I'd forgotten about. This month's article looks at techniques that can be used to harden your mail form, and reduce the chances of it being misused.
How do the spammers find you?
There are two main ways they find you. One of course, is by visiting your site, and following the links. If you have a publicly available contact form, there's not much you can do about this one. The other, surprisingly common, way is through a search engine such as Google. By googling for mail.php, contact.php, and the like, spammers will get a list of likely targets. You can reduce this likelihood by choosing an unusual name. This sort of security by obscurity is certainly not anywhere near sufficient, but I'm a fan as, all else being equal, the less attempts, the less chance of an exploit. You of course can't stop people googling for words such as contact on your web page, which should then lead to your script, but for spammers googling for mail.php and so on it is preferable, as with this one effort, they are able to identify a mail form and a PHP script--and they're fairly certain that the developer hasn't read this article!
Here's a simple HTML form used for sending mail, followed by the script for sending it. It's stripped to its bare minimum for now.
form.html (1)
Email: 
Mail body: 
mail.php (1)
$to      = "bob@domain_example.co.za";
$subject = "Email from website";
$message = $_REQUEST["body"];
$email = $_REQUEST["email"];
 
$headers = "From: $email";
mail($to, $subject, $message, $headers);
echo "Thanks for submitting.";
 
?>
Here's what the results should look like (you can view the message source on your email client to see, with the exception of any bcc field, exactly what was sent).
To: bob@domain_example.co.za
Subject: Email from website
From: sender@their_domain.co.za
However, this form and script combination is a spam relay waiting to happen. Notice that the to address is hard-coded. Many applications allow the user to specify the to address, and this is of course opens the door even further. However, too many people naively assume that hard-coding it is sufficient to avoid spam. This is certainly not true. The script above uses $_REQUEST, which accepts both $_POST and $_GET variables. This is simply to ease the exploit even further for demonstration purposes. It's best to specify $_POST (in the case of our form's example), but limiting a potential spammer to $_GET or $_POST will at best cause an insignificant delay.
Exploiting the script
Assuming the above form and script sit on a server called your-domain.co.za, spammers can simply send the following request:
http://your-domain.co.za/mail.php?body=gotcha&email=barbie@fake-domain.com%0Abcc:spam-1@some-domain.com,spam2@some-domain.com
Let's look at this in more detail. The variable names are available in the form, so the spammer knows to use body and email. The body will contain the contents of the mail (in this case just the single word, gotcha), though of course in practice it would be cheap deals and viagra and the offers of millions if you just supply your bank account details to the ex-wife of some or other dictator.
Next comes the the sneaky bit. The email field, which supposedly just contains the sender's email (in this case barbie@fake-domain.com is used), also contains a bcc field, followed by a comma-delimited list of emails to be spammed. The %0A character is a linefeed.
Here's what the email headers would look like.
To: bob@domain_example.co.za
Subject: Email from website
From: barbie@fake-domain.com
Bcc: spam-1@some-domain.com,spam2@some-domain.com
Without any protection, it's a fairly simple matter for a mail form to be abused. So how can we protect against this? There are a number of things to do, and a number of spammer responses, so I suggest reading through the whole article carefully before making any changes.
Checking for valid email
Since the email field was used to mask the bcc list, and it makes good sense to avoid receiving comments from people who don't bother to put a valid email in, one way to stop this is to test for a valid email. This is not enough, but it's a step closer towards the principle of not trusting any values that the user can edit. The changes are in bold:
mail.php (2)
$to      = "bob@domain_example.co.za";
$subject = "Email from website";
$message = $_REQUEST["body"];
$email = $_REQUEST["email"];
 
function is_valid_email($email) {
  return preg_match('#^[a-z0-9.!\#$%&\'*+-/=?^_`{|}~]+@([0-9.]+|([^\s]+\.+[a-z]{2,6}))$#si', $email);
}
 
if (!is_valid_email($email)) {
  echo 'Sorry, invalid email';
  exit;
}
 
$headers = "From: $email";
mail($to, $subject, $message, $headers);
echo "Thanks for submitting.";
?>
It's too soon to be complacent. Let's change the example slightly by adding a subject field:
form.html (2)
Email: 
Subject: 
Mail body: 
mail.php (3)
$to      = "bob@domain_example.co.za";
$subject = "Email from website";
$message = $_REQUEST["body"];
$subject = $_REQUEST["subject"];
$email = $_REQUEST["email"];
 
function is_valid_email($email) {
  return preg_match('#^[a-z0-9.!\#$%&\'*+-/=?^_`{|}~]+@([0-9.]+|([^\s]+\.+[a-z]{2,6}))$#si', $email);
}
 
if (!is_valid_email($email)) {
  echo 'Sorry, invalid email';
  exit;
}
 
$headers = "From: $email";
mail($to, $subject, $message, $headers);
echo "Thanks for submitting.";
?>
Once again this can be exploited, with something like:


How to avoid all of this spam
It's not just bcc that should worry us. There are other strings that spammers can use. These include: content-type:, mime-version:, multipart/mixed, cc as well as bcc. Spammers prefer bcc, but they don't always mind if everyone sees the full list of addresses they've spammed. I'm not going to focus on demonstrating all the possible exploits, rather, I'll focus on preventing the exploits. Suffice to say there are all sorts of possibilities, including sending HTML attachments and the like. This next addition checks for the existence of certain suspicious strings in any of the submitted values. If they exist, the mail is not sent. Similarly, the existence of newline characters is usually an indication of something unusual going on.
mail.php (4)
$to      = "bob@domain_example.co.za";
$subject = $_REQUEST["subject"];
$body = $_REQUEST["body"];
$email = $_REQUEST["email"];
 
function is_valid_email($email) {
  return preg_match('#^[a-z0-9.!\#$%&\'*+-/=?^_`{|}~]+@([0-9.]+|([^\s]+\.+[a-z]{2,6}))$#si', $email);
}
 
function contains_bad_str($str_to_test) {
  $bad_strings = array(
                "content-type:"
                ,"mime-version:"
                ,"multipart/mixed"
                    ,"Content-Transfer-Encoding:"
                ,"bcc:"
                    ,"cc:"
                    ,"to:"
  );
  
  foreach($bad_strings as $bad_string) {
    if(eregi($bad_string, strtolower($str_to_test))) {
      echo "$bad_string found. Suspected injection attempt - mail not being sent.";
      exit;
    }
  }
}
 
function contains_newlines($str_to_test) {
   if(preg_match("/(%0A|%0D|\\n+|\\r+)/i", $str_to_test) != 0) {
     echo "newline found in $str_to_test. Suspected injection attempt - mail not being sent.";
     exit;
   }
} 
 
if (!is_valid_email($email)) {
  echo 'Invalid email submitted - mail not being sent.';
  exit;
}
 
contains_bad_str($email);
contains_bad_str($subject);
contains_bad_str(body);
 
contains_newlines($email);
contains_newlines($subject);
 
$headers = "From: $email";
mail($to, $subject, $body, $headers);
echo "Thanks for submitting.";
?>
Further hardening
I'm partly hesitant to discuss the next part, as these additions are not strictly speaking necessary. However, I'm in favour of doing them in principle, and they're worth mentioning to get developers thinking along those sorts of lines. They have uses beyond just mail injection. They certainly don't provide a foolproof technique to avoid abuse. They involve doing what you can to ensure that a script is only accessed in the right context. If it should only ever be called as part of a POST procedure, ensure that it tests for this and doesn't permit access if it's anything else. Here's the script with this addition.
mail.php (5)
$to      = "bob@domain_example.co.za";
$subject = $_REQUEST["subject"];
$body = $_REQUEST["body"];
$email = $_REQUEST["email"];
 
$dodgy_strings = array(
                "content-type:"
                ,"mime-version:"
                ,"multipart/mixed"
                ,"bcc:"
);
 
function is_valid_email($email) {
  return preg_match('#^[a-z0-9.!\#$%&\'*+-/=?^_`{|}~]+@([0-9.]+|([^\s]+\.+[a-z]{2,6}))$#si', $email);
}
 
function contains_bad_str($str_to_test) {
  $bad_strings = array(
                "content-type:"
                ,"mime-version:"
                ,"multipart/mixed"
                    ,"Content-Transfer-Encoding:"
                ,"bcc:"
                    ,"cc:"
                    ,"to:"
  );
  
  foreach($bad_strings as $bad_string) {
    if(eregi($bad_string, strtolower($str_to_test))) {
      echo "$bad_string found. Suspected injection attempt - mail not being sent.";
      exit;
    }
  }
}
 
function contains_newlines($str_to_test) {
   if(preg_match("/(%0A|%0D|\\n+|\\r+)/i", $str_to_test) != 0) {
     echo "newline found in $str_to_test. Suspected injection attempt - mail not being sent.";
     exit;
   }
} 
 
if($_SERVER['REQUEST_METHOD'] != "POST"){
   echo("Unauthorized attempt to access page.");
   exit;
}
 
if (!is_valid_email($email)) {
  echo 'Invalid email submitted - mail not being sent.';
  exit;
}
 
contains_bad_str($email);
contains_bad_str($subject);
contains_bad_str(body);
 
contains_newlines($email);
contains_newlines($subject);
 
$headers = "From: $email";
mail($to, $subject, $body, $headers);
echo "Thanks for submitting.";
?>
Similarly, if your mail script should only ever be called from a particular page, check to see if the user is coming from the right referer. Any attempt to directly access the page, or call it from any other page, should also result in an error, with further access denied. This sort of thing can be done with PHP, but is perhaps best done through the web server itself. However, the referer can also be faked. A further suggestion, which I've never implemented myself but makes a lot of sense, is to do some form of IP checking. If the IP has not visited the specific page shortly prior to calling the script, deny access. This avoids the problem of using a fake referer and going directly to the mail script.
Conclusion
Of course there are all sorts of things that you can do to enhance this script. You may want to log spam attempts either to a file or database. Useful data to capture includes the IP, referrer, user-agent, request string and request method. The request string can provide great insight into the minds of the spammers, as there will usually be quite a few attempts from the same source. The effort is worth it for the spammer, as they're putting in the work hoping to get a long-term benefit - a script that they can continue to exploit for a long time. Implement these changes, and your scripts should be a lot more secure - but don't sit back after that. Keep your eyes open. Security needs constant attention! Good luck.

19 February 2010

Basic RAC Commands

Starting Up and Shutting Down with SRVCTL
Enter the following SRVCTL syntax from the command line, providing the required
database name and instance name, or include multiple instance names to start
multiple specific instances:

For administrator-managed databases, enter a comma-delimited list of instance names:

$ srvctl start instance -d db_unique_name -i instance_name_list [-o start_options]

In Windows you must enclose a comma-delimited list in double quotation marks ("").
For policy-managed databases, enter a single node name:

$ srvctl start instance -d db_unique_name -n node_name [-o start_options]

Note that this command also starts all enabled and non-running services that have
AUTOMATIC management policy, and for which the database role matches one of the
service's roles.

To stop one or more instances, enter the following SRVCTL syntax from the command
line:

$ srvctl stop instance -d db_unique_name [ -i "instance_name_list" |
-n node_name ] [ -o stop_options ]

You can enter either a comma-delimited list of instance names to stop several instances
or you can enter a node name to stop one instance. In Windows you must enclose a
comma-delimited list in double quotation marks ("").

This command also stops the services related to the terminated instances on the nodes
where the instances were running. As an example, the following command shuts
down the two instances, orcl3 and orcl4, on the orcl database using the
immediate stop option:

$ srvctl stop instance -d orcl -i "orcl3,orcl4" -o immediate

To start or stop your entire cluster database, that is, all of the instances and its enabled
services, enter the following SRVCTL commands:

$ srvctl start database -d db_unique_name [-o start_options]
$ srvctl stop database -d db_unique_name [-o stop_options]

The following SRVCTL command, for example, mounts all of the non-running
instances of an Oracle RAC database:

$ srvctl start database -d orcl -o mount


Verifying That Instances are Running
To verify that instances are running, on any node from a SQL*Plus prompt enter the
following, where password is the password:

CONNECT SYS/as SYSDBA
Enter password: password
SELECT * FROM V$ACTIVE_INSTANCES;

This query returns output similar to the following:
INST_NUMBER INST_NAME
----------- -----------------
1 db1-sun:db1
2 db2-sun:db2
3 db3-sun:db3

The output columns for this example are shown in Table 3–2.

Table 3–2 Descriptions of V$ACTIVE_INSTANCES Columns
Column Description


Column
Description
INST_NUMBER
Identifies the instance number.
INST_NAME
Identifies the host name and instance name as host_name:instance_name.


Terminating Sessions On a Specific Cluster Instance

You can use the ALTER SYSTEM KILL SESSION statement to terminate a session on
a specific instance. When a session is terminated, any active transactions of the session
are rolled back, and resources held by the session (such as locks and memory areas)
are immediately released and available to other sessions.
Using this statement enables you to maintain strict application service-level
agreements in Oracle RAC environments. Often, the goal of a service-level agreement
is to execute a transaction in a specified time limit. In an Oracle RAC environment, this
may require terminating a transaction on an instance and retrying the transaction on
another instance within a specified time frame.
To terminate sessions, follow these steps:

Query the value of the INST_ID column in the GV$SESSION dynamic
performance view to identify which session to terminate
Issue the ALTER SYSTEM KILL SESSION and specify the session index number
(SID) and serial number of a session that you identified with the GV$SESSION
dynamic performance view.
KILL SESSION 'integer1, integer2[, @integer3]'
For integer1, specify the value of the SID column.
For integer2, specify the value of the SERIAL# column.
For the optional integer3, specify the ID of the instance where the session to
be killed exists. You can find the instance ID by querying the GV$ tables.
To use this statement, your instance must have the database open, and your
session and the session to be terminated must be on the same instance unless you
specify integer3.

If the session is performing some activity that must be completed, such as waiting for
a reply from a remote database or rolling back a transaction, then Oracle Database
waits for this activity to complete, marks the session as terminated, and then returns
control to you. If the waiting lasts a minute, then Oracle Database marks the session to
be terminated and returns control to you with a message that the session is marked to be terminated. The PMON background process then marks the session as terminated when the activity is complete.

16 February 2010

Download and Install Oracle Application Express



To install Oracle Application Express:
1. Download the file apex_3.2.zip from the Oracle Application Express download
page. See:
http://www.oracle.com/technology/products/database/application_
express/download.html
Note that the actual file name may differ if a more recent release has shipped since
this document was published.
2. Unzip apex_3.2.zip as follows, preserving directory names:
UNIX and Linux: Unzip apex_3.2.zip
Windows: Double click the file apex_3.2.zip in Windows Explorer
3. Change your working directory to apex.
4. Start SQL*Plus and connect to the database where Oracle Application Express is
installed as SYS specifying the SYSDBA role. For example:
On Windows:
SYSTEM_DRIVE:\ sqlplus /nolog
SQL> CONNECT SYS as SYSDBA
Enter password: SYS_password
On UNIX and Linux:
$ sqlplus /nolog
SQL> CONNECT SYS as SYSDBA
Enter password: SYS_password
5. Disable any existing password complexity rules for the default profile. See
"Configuring Password Protection" in Oracle Database Security Guide.
6. Select the appropriate installation option.
Full development environment provides complete access to the Application
Builder environment to develop applications. A Runtime environment enables
users to run applications that cannot be modified. To learn more, see "About the
Oracle Application Express Runtime Environment" on page 1-2.
Available installation options include:
Full development environment. Run apexins.sql passing the following
four arguments in the order shown:
@apexins tablespace_apex tablespace_files tablespace_temp images
Where:
See Also: "About the Oracle Application Express Runtime
Environment" on page 1-2
Downloading from OTN and Configuring the Embedded PL/SQL Gateway
3-4 Oracle Application Express Installation Guide
tablespace_apex is the name of the tablespace for the Oracle
Application Express application user.
tablespace_files is the name of the tablespace for the Oracle
Application Express files user.
tablespace_temp is the name of the temporary tablespace.
images is the virtual directory for Oracle Application Express images. To
support future Oracle Application Express upgrades, define the virtual
image directory as /i/.
Example:
@apexins SYSAUX SYSAUX TEMP /i/
Runtime environment. Run apxrtins.sql passing the following arguments
in the order shown:
@apxrtins tablespace_apex tablespace_files tablespace_temp images
Where:
tablespace_apex is the name of the tablespace for the Oracle
Application Express application user.
tablespace_files is the name of the tablespace for the Oracle
Application Express files user.
tablespace_temp is the name of the temporary tablespace.
images is the virtual directory for Oracle Application Express images. To
support future Oracle Application Express upgrades, define the virtual
image directory as /i/.
Example:
@apxrtins SYSAUX SYSAUX TEMP /i/
When Oracle Application Express installs it creates three new database accounts:
APEX_030200 - The account that owns the Oracle Application Express schema
and metadata.
FLOWS_FILES - The account that owns the Oracle Application Express uploaded
files.
APEX_PUBLIC_USER - The minimally privileged account used for Oracle
Application Express configuration with Oracle HTTP Server and mod_plsql.
If you are upgrading from a previous release, FLOWS_FILES, already exists and
APEX_PUBLIC_USER is created if it does not already exist.
See Also: Oracle Database PL/SQL Language Reference for more
information about SQL*Plus
Tip: Oracle Application Express must be installed from a writable
directory on the file system. See "Reviewing a Log of an Installation
Session" on page A-1.
Downloading from OTN and Configuring the Embedded PL/SQL Gateway
Downloading from Oracle Technology Network 3-5


Change the Password for the ADMIN Account


In a new installation of Oracle Application Express, or if you are converting a runtime
environment to a development environment, you must change the password of the
internal ADMIN account. In an upgrade scenario, the password will be preserved and
carried over from the prior release.
To change the password for the ADMIN account:
1. Change your working directory to the apex directory where you unzipped the
installation software.
2. Start SQL*Plus and connect to the database where Oracle Application Express is
installed as SYS specifying the SYSDBA role. For example:
On Windows:
SYSTEM_DRIVE:\ sqlplus /nolog
SQL> CONNECT SYS as SYSDBA
Enter password: SYS_password
On UNIX and Linux:
$ sqlplus /nolog
SQL> CONNECT SYS as SYSDBA
Enter password: SYS_password
3. Run apxchpwd.sql. For example:
@apxchpwd
When prompted enter a password for the ADMIN account.



Restart Processes

After you install Oracle Application Express, you must restart the processes that you
stopped before you began the installation, such as listener and other processes.