CodeCharge Studio
search Register Login  

Visual Web Reporting

Visually create Web Reports in PHP, ASP, .NET, Java, Perl and ColdFusion.
CodeCharge.com

YesSoftware Forums -> CodeCharge Studio -> General/Other

 [SOLVED] How to mask credit card numbers

Print topic Send  topic

Author Message
JimmyCrackedCorn

Posts: 583
Posted: 06/02/2008, 10:43 AM

I have a credit card field on my Edit record page.

In the "Before Show" event I am masking the number so it looks like this,

************1234

This way the operator can edit the credit card but they cannot see what was there before.

If they enter a new credit card number everything is fine.

BUT, if they do not need to edit the credit card number I need to detect that the number is masked and then simply remove that field from the Update.

I do this all thie time in my own custom code; is this possible with CCS?
_________________
Walter Kempees...you are dearly missed.
View profile  Send private message
datadoit
Posted: 06/02/2008, 11:06 AM

Welp, the first thing that comes to my mind on how to deal with this is
to include a hidden field in your form, then update/insert the value
from that hidden field and not the 'display' field. Don't bind the
'display' field to a database field - continue to use your BeforeShow
event to get the current value and then mask it.

In the form's OnValidate event, add code to check the field value versus
what the database value is, and then copy that value to the hidden
field's value. Something like:

$db = new clsDBInternetDB();
$FieldValue = CCGetFromPost("YourField","");
$DatabaseValue = CCDLookUp("YourField", "YourTable", "YourID=" .
$db->ToSQL($Container->YourUniqueField->GetValue(), ccsInteger), $db);

if (substr($FieldValue,0,3) != "***" AND $FieldValue != $DatabaseValue) {
$Container->YourHiddenField->SetValue($FieldValue);
}
else {
$Container->YourHiddenField->SetValue($DatabaseValue);
}

$db->close();

That's kinda crudamentary, but I think you'll see the idea.

JimmyCrackedCorn

Posts: 583
Posted: 06/02/2008, 1:04 PM

hmmm, very clever idea! however, I'm not sure it addresses my issue.

case #1
-user opens the record page and sees the masked credit card number
-the credit card number needs to be changed so the user changes it
-user clicks the submit button
-everything works OK and credit card number is updated in database

case #2
-user opens the record page and sees the masked credit card number
-the credit card number does NOT need to be changed
-user makes other changes on the form and clicks the submit button
-credit card number has "***" in it so it does not validate properly
-if I blank it that causes errors
-since I do not know the number (remember it was masked on the server before being transmitted) I cannot process it

In case #2 I'd like to simply tell the Update event NOT to process this field at all. This is what I do in my custom code...I just drop that field from the Update command.
_________________
Walter Kempees...you are dearly missed.
View profile  Send private message
datadoit
Posted: 06/02/2008, 2:37 PM

JimmyCrackedCorn wrote:
> -credit card number has "***" in it so it does not validate properly
> -if I blank it that causes errors
-----------------------

It sounds like you have other validations going on for the credit card
field (which is good). So you're going to have to update your
validation to compensate for the new validation in the form's OnValidate
event, or place the example I posted into the field's OnValidate event,
or a combination of both.

Just remember that the field validation will occur before the form's
validation event. The concept remains the same: Update a hidden field
that will actually post to the database based on your validation rules
and whether or not the field value changed.

Don't forget to 'unbind' your display field from the database (ie: don't
set a control source).
JimmyCrackedCorn

Posts: 583
Posted: 06/02/2008, 3:20 PM

maybe I'm not explaining this clearly,

on the server I mask the card number and DO NOT send the actual card number to the web browser (to do so would invalidate all of the security)

when the user decides NOT to update the card number, the only thing I have to send back to the database is the masked number which will not work!

what I need to be able to do is change the SQL BEFORE the Update to remove the card number field from the command since I cannot give it a valid value. I was hoping CCS would have something to do this like the CCRemoveParam Function.

I cannot see any other way this can work. Unless I am really missing somehting the only way your suggestion would work is if I put the credit card number in the hidden field and obviously I cannot do that. Is there something here I am not seeing?
_________________
Walter Kempees...you are dearly missed.
View profile  Send private message
datadoit
Posted: 06/02/2008, 3:54 PM

JimmyCrackedCorn wrote:
> Unless I am really missing somehting
> the only way your suggestion would work is if I put the credit card number in
> the hidden field and obviously I cannot do that.
> ---------------------------------------

Why not? :)

The example provided shows you how to post changed data as asked. Any
other security issues or rules that you're bound by are beyond the
specifications given in your original request.

There is no way within CCS to -conditionally- control the Update/Insert
operations without custom coding (ie: Custom Update/Insert). While
there are the InsertAllowed or UpdateAllowed run-time properties, they
only apply to the entire form. Perhaps this could be a nice feature
request - apply this property setting to an individual control within a
form:

$Component->UpdateAllowed = false;
marcwolf


Posts: 361
Posted: 06/02/2008, 4:05 PM

Hi..
Try this.

When you load the record put the credit card number into a session variable, and put the masked credit card number into two fields.. A Hidden one and a text one.

When the form is submitted you can check that the two credit card fields are the same. If so then put the session variable back into the credit card field using the BeforeInsert of BeforeUpdate event.

If the two fields are different then you can put the new creditcard number into the database, update the session with the new number, and then send the two masked fields back out again.

This way you have your validation AND your application is secure as the credit card number is stored in the server memory - not on the Client's browser.

Hope this helps

Dave
_________________
' Coding Coding Coding
Keep Those Keyboards Coding.
Raw Code!!!!!!!
View profile  Send private message
wkempees


Posts: 1679
Posted: 06/02/2008, 4:24 PM

BeforeExecuteUpdate, is the place to alter the SQL.

First I would do
  
echo (SQL generated: ". $Component->ds->SQL;  
This will display the generated UPDATE statement,
UPDATE <table> SET field=value, [....] WHERE ......

So test for creditcardfield
  
if ( substr($Component->yourfield->GetValue(),1,3) == "***") {  
   $OrgSQL = $Component->ds->SQL;  
   $FldString = " creditcardnr = " . $Component->ds->ToSQL($Component->yourfield->GetValue(), ccsText) . ",";  
   $Component->ds->SQL = str_replace($FldString,"", $OrgSQL);  
//  echo "<br> Org: ". $OrgSQL;  
// echo "Fldstring" . $FldString;  
// echo "<br> New"  . $Component->ds->SQL;  
  
}  
  

Basics:
Store the original SQL
strore the 'field = value' in $Fldstring and use ToSQL to make a correct string
replace the $fldString with nothing "" actually cutting it out of the update SQL
feed CCS the new SQL

The echo statements are for debugging only, of course. will display and stop execute.


an example on Internet example database, Store products Update:
  
if ( 1 == 1) { // stupid always true test  
   $OrgSQL = $Component->ds->SQL;  
   $FldString = " product_name = " . $Component->ds->ToSQL($Component->product_name->GetValue(),ccsText) . ",";  
   $Component->ds->SQL = str_replace($FldString,"", $OrgSQL);  
  
   echo "<br> Org: ". $OrgSQL;  
   echo "<br> Fldstring" . $FldString;  
   echo "<br> New"  . $Component->ds->SQL;  
}  
  
Results in:  
  
  
Org: UPDATE store_products SET category_id = 1, product_name = 'PHP and MySQL Web Development', price = 3, description = NULL, is_recommended = 0 WHERE product_id = 5  
Fldstring product_name = 'PHP and MySQL Web Development',  
NewUPDATE store_products SET category_id = 1,price = 3, description = NULL, is_recommended = 0 WHERE product_id = 5  
Warning: Cannot modify header information - headers already sent by (output sta................  
  

Walter
HTH




_________________
Origin: NL, T:GMT+1 (Forumtime +9)
CCS3/4.01.006 PhP, MySQL .Net/InMotion(Vista/XP, XAMPP)

if you liked this info PAYPAL me: http://donate.consultair.eu
View profile  Send private message
JimmyCrackedCorn

Posts: 583
Posted: 06/02/2008, 5:58 PM

Quote datadoit:
Why not? :)

in my original post I stated that this is credit card data. if I put someone's credit card number in a hidden field and sent it back to the browser it seems to me this is defeating the whole purpose of masking the data! if I did that wouldn't the user be able to view source in the browser and read the value from the hidden field?
_________________
Walter Kempees...you are dearly missed.
View profile  Send private message
JimmyCrackedCorn

Posts: 583
Posted: 06/02/2008, 5:59 PM

Quote marcwolf:
Hi..
Try this.

When you load the record put the credit card number into a session variable, and put the masked credit card number into two fields.. A Hidden one and a text one.

When the form is submitted you can check that the two credit card fields are the same. If so then put the session variable back into the credit card field using the BeforeInsert of BeforeUpdate event.

If the two fields are different then you can put the new creditcard number into the database, update the session with the new number, and then send the two masked fields back out again.

This way you have your validation AND your application is secure as the credit card number is stored in the server memory - not on the Client's browser.

Hope this helps

Dave

I like the sound of this. Secure and sounds fairly easy to implement. I'll give it a try. Thanks!
_________________
Walter Kempees...you are dearly missed.
View profile  Send private message
JimmyCrackedCorn

Posts: 583
Posted: 06/02/2008, 6:00 PM

Quote wkempees:
BeforeExecuteUpdate, is the place to alter the SQL.

First I would do
  
echo (SQL generated: ". $Component->ds->SQL;  
This will display the generated UPDATE statement,
UPDATE <table> SET field=value, [....] WHERE ......

So test for creditcardfield
  
if ( substr($Component->yourfield->GetValue(),1,3) == "***") {  
   $OrgSQL = $Component->ds->SQL;  
   $FldString = " creditcardnr = " . $Component->ds->ToSQL($Component->yourfield->GetValue(), ccsText) . ",";  
   $Component->ds->SQL = str_replace($FldString,"", $OrgSQL);  
//  echo "<br> Org: ". $OrgSQL;  
// echo "Fldstring" . $FldString;  
// echo "<br> New"  . $Component->ds->SQL;  
  
}  
  

Basics:
Store the original SQL
strore the 'field = value' in $Fldstring and use ToSQL to make a correct string
replace the $fldString with nothing "" actually cutting it out of the update SQL
feed CCS the new SQL

The echo statements are for debugging only, of course. will display and stop execute.


an example on Internet example database, Store products Update:
  
if ( 1 == 1) { // stupid always true test  
   $OrgSQL = $Component->ds->SQL;  
   $FldString = " product_name = " . $Component->ds->ToSQL($Component->product_name->GetValue(),ccsText) . ",";  
   $Component->ds->SQL = str_replace($FldString,"", $OrgSQL);  
  
   echo "<br> Org: ". $OrgSQL;  
   echo "<br> Fldstring" . $FldString;  
   echo "<br> New"  . $Component->ds->SQL;  
}  
  
Results in:  
  
  
Org: UPDATE store_products SET category_id = 1, product_name = 'PHP and MySQL Web Development', price = 3, description = NULL, is_recommended = 0 WHERE product_id = 5  
Fldstring product_name = 'PHP and MySQL Web Development',  
NewUPDATE store_products SET category_id = 1,price = 3, description = NULL, is_recommended = 0 WHERE product_id = 5  
Warning: Cannot modify header information - headers already sent by (output sta................  
  

Walter
HTH

This sounds interesting too. I'm an ASP programmer so I'll try and understand your code enough to give it a try.
_________________
Walter Kempees...you are dearly missed.
View profile  Send private message
datadoit
Posted: 06/03/2008, 8:00 AM

JimmyCrackedCorn wrote:
> in my original post I stated that this is credit card data. if I put someone's
> credit card number in a hidden field and sent it back to the browser it seems to
> me this is defeating the whole purpose of masking the data! if I did that
> wouldn't the user be able to view source in the browser and read the value from
> the hidden field?
> ---------------------------------------

You are correct. Excellent point!

To make certain it's secure in that regards, in the hidden field's
BeforeShow event, do:

$Component->SetValue("");

It's still 'bound' to the database field, but it doesn't get it's value
until -after- the submit takes place.
wkempees


Posts: 1679
Posted: 06/03/2008, 9:40 AM

Quote :
ASP
When using ASP, you can use the following code to print out variables within most events:
  
response.write variable_name  

In a similar fashion you can also display the value of a control, such as a Text Box, within its Before Show event:
  
response.write TextBox1.value  
Additionally, you can use the Before Execute Select event of a Grid to examine parts of the SQL statement of the form by using the following code:
  
response.write "SQL:" & GridName.datasource.SQL & "<br>"  
response.write "ORDER BY:" & GridName.datasource.Order & "<br>"  
response.write "WHERE:" & GridName.datasource.Where & "<br>"  

(similar code can also be used to dynamically alter the SQL)

Keep in mind that sometimes the VBScript command response.write may appear not to work, especially when the page is being redirected to another page or refreshed. In this case you can disable the page buffering option by adding the following code to the beginning of the Common.asp file (after the 'End Include Files comment):
  
response.buffer = False  



_________________
Origin: NL, T:GMT+1 (Forumtime +9)
CCS3/4.01.006 PhP, MySQL .Net/InMotion(Vista/XP, XAMPP)

if you liked this info PAYPAL me: http://donate.consultair.eu
View profile  Send private message
JimmyCrackedCorn

Posts: 583
Posted: 06/03/2008, 10:34 AM

Quote datadoit:
You are correct. Excellent point!

To make certain it's secure in that regards, in the hidden field's
BeforeShow event, do:

$Component->SetValue("");

It's still 'bound' to the database field, but it doesn't get it's value
until -after- the submit takes place.
but if I set the hidden field value to "" then upon return to the server it will blank the credit card number in the database!

as I see it there are only two ways to do this, 1) rewrite the SQL to remove this field when it has not been changed (like Walter suggested) or 2) store the credit card number on the server for later comparison (as MarcWolf suggested). I was hoping CCS has a command to simply remove one of the fields from the Update SQL.

thanks for your suggestions but I just do not see how they could work since the data must be handled securely.
_________________
Walter Kempees...you are dearly missed.
View profile  Send private message
JimmyCrackedCorn

Posts: 583
Posted: 06/03/2008, 10:47 AM

walter,

thanks for the additional info. but I am experiencing something strange (at least to me!)

using your statements in the BeforeExecuteUpdate event I get the following

SQL:SELECT * FROM users {SQL_Where} {SQL_OrderBy}
ORDER BY:
WHERE:user_username = 'LuckyDawg123'

but this is an edit record form! why would the SQL be SELECT? I expected UPDATE
_________________
Walter Kempees...you are dearly missed.
View profile  Send private message
datadoit
Posted: 06/03/2008, 12:45 PM

JimmyCrackedCorn wrote:
> but if I set the hidden field value to "" then upon return to the server it
> will blank the credit card number in the database!
>
> as I see it there are only two ways to do this, 1) rewrite the SQL to remove
> this field when it has not been changed (like Walter suggested) or 2) store the
> credit card number on the server for later comparison (as MarcWolf suggested). I
> was hoping CCS has a command to simply remove one of the fields from the Update
> SQL.
>
> ---------------------------------------

Recognize that you're setting it's initial value in the field's
BeforeShow event to null so that a client's view source won't expose
anything (as requested), but then in the form's OnValidate server-side
event you're giving it a value (either the new value or the old value
from the database). It's never exposed to the client.

Looking at this further, you don't even need a hidden field! Simply use
the existing display field, give it a mask as you have been in it's
BeforeShow event, then assign the field value accordingly (old or new
value).

//Get what's currently in the database.
$db = new clsDBYourConnectionDB();
$DatabaseValue = CCDLookUp("YourField", "YourTable", "YourID=" .
$db->ToSQL($Container->YourUniqueField->GetValue(), ccsInteger), $db);
$db->close();

//Now let's see if user changed something.
if (substr($Container->YourField->GetValue(),0,3) == "***") {
//There's no change, so write out the existing database value.
$Container->YourField->SetValue($DatabaseValue);
}

//Otherwise the update will write out the new value.
JimmyCrackedCorn

Posts: 583
Posted: 06/03/2008, 1:24 PM

Quote datadoit:
JimmyCrackedCorn wrote:
> but if I set the hidden field value to "" then upon return to the server it
> will blank the credit card number in the database!
>
> as I see it there are only two ways to do this, 1) rewrite the SQL to remove
> this field when it has not been changed (like Walter suggested) or 2) store the
> credit card number on the server for later comparison (as MarcWolf suggested). I
> was hoping CCS has a command to simply remove one of the fields from the Update
> SQL.
>
> ---------------------------------------

Recognize that you're setting it's initial value in the field's
BeforeShow event to null so that a client's view source won't expose
anything (as requested), but then in the form's OnValidate server-side
event you're giving it a value (either the new value or the old value
from the database). It's never exposed to the client.

Looking at this further, you don't even need a hidden field! Simply use
the existing display field, give it a mask as you have been in it's
BeforeShow event, then assign the field value accordingly (old or new
value).

//Get what's currently in the database.
$db = new clsDBYourConnectionDB();
$DatabaseValue = CCDLookUp("YourField", "YourTable", "YourID=" .
$db->ToSQL($Container->YourUniqueField->GetValue(), ccsInteger), $db);
$db->close();

//Now let's see if user changed something.
if (substr($Container->YourField->GetValue(),0,3) == "***") {
//There's no change, so write out the existing database value.
$Container->YourField->SetValue($DatabaseValue);
}

//Otherwise the update will write out the new value.


so if I understand, you are saying do a custom query to retrieve the current field value before allowing the update to occur and if there is no change overwrite the masked value with what you got from the database. then let the update continue. is that correct?
_________________
Walter Kempees...you are dearly missed.
View profile  Send private message
datadoit
Posted: 06/03/2008, 3:32 PM

JimmyCrackedCorn wrote:
> so if I understand, you are saying do a custom query to retrieve the
current
> field value before allowing the update to occur and if there is no change
> overwrite the masked value with what you got from the database. then let the
> update continue. is that correct?
> ---------------------------------------

Correct. You don't even need the custom query if you don't want to.
Simply define a global variable in the field's BeforeShow and set that
global variable to the field value. Then, in the field's OnValidate,
use that global variable to compare with.

YourField_BeforeShow:
global $DatabaseValue;
$DatabaseValue = $Component->GetValue();
....then do your masking stuff

YourField_OnValidate:
global $DatabaseValue;
//Now let's see if user changed something.
if (substr($Container->YourField->GetValue(),0,3) == "***") {
//There's no change, so write out the existing database value.
$Container->YourField->SetValue($DatabaseValue);
}
wkempees


Posts: 1679
Posted: 06/03/2008, 5:40 PM

@J
ASP apparently has different events happening at different moments.
Try same at BeforeUpdate event, at least the response.write of the SQL, let me know.
But do datadoit's first, sounds as good a solution.

Walter


_________________
Origin: NL, T:GMT+1 (Forumtime +9)
CCS3/4.01.006 PhP, MySQL .Net/InMotion(Vista/XP, XAMPP)

if you liked this info PAYPAL me: http://donate.consultair.eu
View profile  Send private message
JimmyCrackedCorn

Posts: 583
Posted: 06/03/2008, 9:52 PM

Quote datadoit:
Correct. You don't even need the custom query if you don't want to.
Simply define a global variable in the field's BeforeShow and set that
global variable to the field value. Then, in the field's OnValidate,
use that global variable to compare with.

YourField_BeforeShow:
global $DatabaseValue;
$DatabaseValue = $Component->GetValue();
....then do your masking stuff

YourField_OnValidate:
global $DatabaseValue;
//Now let's see if user changed something.
if (substr($Container->YourField->GetValue(),0,3) == "***") {
//There's no change, so write out the existing database value.
$Container->YourField->SetValue($DatabaseValue);
}

OK. you lost me again! :)

Since one step is before the page/form is sent to the browser and the other step is after the form has been submitted how would a global variable retain its value throughout this process? does CCS automatically persist global variables for me?
_________________
Walter Kempees...you are dearly missed.
View profile  Send private message
JimmyCrackedCorn

Posts: 583
Posted: 06/03/2008, 9:57 PM

A BIG thanks to datadoit, Dave and Walter. It is pretty amazing to get three viable solutions so quickly! I hope I can give back such valuable support to others some day.

For my project I am implementing datadoit's suggestion as it seems to be the simplest overall. Just a few lines of code and minor changes to my validation routines. But I think any of the three suggestions would have resolved this for me.

Thanks again!!!!
_________________
Walter Kempees...you are dearly missed.
View profile  Send private message
datadoit
Posted: 06/04/2008, 5:42 AM

JimmyCrackedCorn wrote:
> OK. you lost me again! :)
>
> Since one step is before the page/form is sent to the browser and the other
> step is after the form has been submitted how would a global variable retain its
> value throughout this process? does CCS automatically persist global variables
> for me?
> ---------------------------------------

Good point! I don't know. :)
Oper


Posts: 1195
Posted: 06/04/2008, 9:45 AM

if i have to doit (i will do this way) (ASP)

The Field to enter the Credit Card in not a Field just a Simple TEXTBOX

to get the Credit and later mask:
on before show event
TEXTBOX=ccdlookup("ccnumberENCRYPT","TABLE","where",YourConnection1)
TEXTBOX=DECRYT(TEXTBOX)
Sender.Value=MASK(TEXTBOX)


and after UPDATE event
TEXTBOX=Encrypt(TEXTBOX)
yourSQL="UPDATE TABLE SET ccnumberENCRYPT=yourtextbox whereHere'
YourCOnnection1.Execute(YourSQL)


will work ok


Of course update only if CC is different from the database

PS:This way CC is never on the HTML
_________________
____________________________
http://www.7bz.com (Free CMS,CRM Developed in CCS)

http://www.PremiumWebTemplate.com
Affiliation Web Site Templates

Please do backup first
View profile  Send private message
wkempees


Posts: 1679
Posted: 06/04/2008, 3:18 PM

@Oper, nice one, thanks.
@J, pls change title to [SOLVED] How to mask creditcard numbers.

The [SOLVED] is serious, the other part is changed by the SQL, lol

Walter
_________________
Origin: NL, T:GMT+1 (Forumtime +9)
CCS3/4.01.006 PhP, MySQL .Net/InMotion(Vista/XP, XAMPP)

if you liked this info PAYPAL me: http://donate.consultair.eu
View profile  Send private message
JimmyCrackedCorn

Posts: 583
Posted: 06/04/2008, 10:17 PM

Quote wkempees:
@Oper, nice one, thanks.
@J, pls change title to [SOLVED] How to mask creditcard numbers.

The [SOLVED] is serious, the other part is changed by the SQL, lol

Walter
I'll change it after I finish this part of the project (just in case everything does not go so smooth!)
_________________
Walter Kempees...you are dearly missed.
View profile  Send private message
JimmyCrackedCorn

Posts: 583
Posted: 06/16/2008, 12:04 PM

again, thanks to everyone who offered help on this problem. I based my solution on the suggestions offered by datadoit and it worked out really well!

basically it goes like this,

1) in BeforeShow, mask the credit card number

2) in OnValidate, skip validation if credit card number remains masked (that means the users did not change it)

3) in BeforeUpdate, get old credit card number from database with CCDLookUp and compare it to the new number

4) if the new number is masked then set the credit card field.Value to the old number

Very clean. Easy to implement. Completely secure.
_________________
Walter Kempees...you are dearly missed.
View profile  Send private message

Add new topic Subscribe to topic   


These are Community Forums for users to exchange information.
If you would like to obtain technical product help please visit http://support.yessoftware.com.

PHP Reports

Visually create Web Reports in PHP, ASP, .NET, Java, Perl and ColdFusion.
CodeCharge.com

Home   |    Search   |    Members   |    Register   |    Login


Powered by UltraApps Forum created with CodeCharge Studio
Copyright © 2003-2004 by UltraApps.com  and YesSoftware, Inc.