Secure Audit Log SMS Proxy
Learn how to create a cryptographically verifiable audit trail of Twilio-powered SMS conversations using the Secure Audit Log service and redact sensitive information in real time with the Redact Service. By publishing conversation hashes to the blockchain you can provide irrefutable evidence of what was said between two parties without actually exposing the contents of the conversation publicly. With Pangea’s Secure Audit Log SDK, you can deliver the power of the blockchain to your users with a few lines of code. In this tutorial, you’ll build an SMS forwarding service that logs messages between two parties and optionally configure it to redact sensitive or personally identifiable information (PII) in real-time with Pangea's Redact Rulesets.
Requirements
- A free Pangea account
- A Pangea
Domain
andAccess Token
with access rights to both the Audit and Redact service. To learn how to create an account and configure the Audit service visit the Getting Started guide. - A free or paid Twilio account and phone number.
- Python3 installed on your machine.
- The Django web framework
- A free ngrok account and client installed.
Get the sample code
Step 1: Clone the Pangea Builders sample repo from GitHub:
git clone https://github.com/pangeacyber/audit-sms-proxy.git
Step 2: Change the working directory to the Django project with the following command:
cd audit-sms-proxy/python
Take a moment to explore the project files and configure it to your environments.
- manage.py - Django's command-line utility for administrative tasks, such as running a development web server
- .env - Contains the environment variables the app will reference.
- audit/views.js - The application source file that contains a single function to handle incoming SMS messages.
Step 3: Install the Python modules used by the application:
From the root of the project directory run each of the following commands to install each dependency.
To install the Pangea SDK:
pip3 install pangea-sdk
To install the Django web framework:
pip3 install Django
To install the Twilio SDK:
pip3 install twilio
To install the dotenv module you’ll use to load the .env file into environment variables:
pip3 install python-dotenv
Configure and deploy the app
The application source reads 6 variables from the .env file.
ACCOUNT_SID
andAUTH_TOKEN
to authenticate your app with the Twilio service.PANGEA_DOMAIN
andPANGEA_AUTH_TOKEN
to authenticate with the Pangea service.TARGET_NUMBER
andOWNER_NUMBER
are used to determine where to forward incoming SMS messages.
Modify the .env file by replacing each {REPLACE}
tag with the corresponding value. For the PANGEA_
specific variables, use the three values you noted in the Getting Started guide, or retrieve them from the Pangea Console by navigating to the Secure Audit Log tab. The Twilio values for ACCOUNT_SID
and AUTH_TOKEN
can be found on the landing page of the Twilio Console . OWNER_NUMBER
and TARGET_NUMBER
should each be a valid E.164 phone number you’d like to test with. For example, OWNER_NUMBER
can be set to your mobile phone number and TARGET_NUMBER
to a friend's number who you’d like to start and record an auditable message thread with. An example of an E.164 formatted number in the US is +16502223333.
NOTE: You can also set both
OWNER_NUMBER
andTARGET_NUMBER
to your mobile number and reply to your own messages.
Verify your changes to the .env file with the git diff
sub-command:
git diff
The output should look similar to this:
diff --git a/.env b/.env
index 7442c6a..9fd8304 100644
--- a/.env
+++ b/.env
@@ -1,6 +1,6 @@
-TWILIO_ACCOUNT_SID={REPLACE}
-TWILIO_AUTH_TOKEN={REPLACE}
-PANGEA_DOMAIN={REPLACE}
-PANGEA_AUTH_TOKEN={REPLACE}
-OWNER_NUMBER={REPLACE}
-TARGET_NUMBER={REPLACE}
+TWILIO_ACCOUNT_SID=ACXXXXXXXXXXXXXXXXXXXXXXXXXX
+TWILIO_AUTH_TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXX
+PANGEA_DOMAIN=aws.us.pangea.cloud
+PANGEA_AUTH_TOKEN=pts_XXXXXXXXXXXXXXXXXXXXXXXX
+OWNER_NUMBER=+1305XXXXXXX
+TARGET_NUMBER=+1305XXXXXXX
Code walkthrough
Inspect the contents of the /audit/views.py source file. The user-defined environment variables set in the .env file will be loaded by the load_dotenv()
function.
# Load the .env file into environment variables
from dotenv import load_dotenv
load_dotenv()
Then, read each of the configured numbers into local variables.
# Read the target recipients numbers from environment variables
ownerNumber = os.getenv("OWNER_NUMBER")
targetNumber = os.getenv("TARGET_NUMBER")
The PANGEA_
values are assigned to their respective variables and the Pangea SDK classes are imported. A PangeaConfig
object is created and used to create an Audit
instance.
# Read the Pangea Domain and Auth Token from the environment variables
pangeaDomain = os.getenv("PANGEA_DOMAIN")
auditToken = os.getenv("PANGEA_AUTH_TOKEN")
# Import the Pangea SDK
from pangea.config import PangeaConfig
from pangea.services import Audit
from pangea.services.audit import Event
from pangea.services.audit import AuditException
# Instantiate a Pangea Configuration object with the end point domain
auditConfig = PangeaConfig(domain=pangeaDomain)
auditService = Audit(auditToken, config=auditConfig)
Similarly, the TWILIO_
account variables are read and set to accountSid
and authToken
, respectively, and used to represent an instance of the Client
class defined in the Twilio SDK.
# Read the Twilio SID and Auth Token from the environment variables
accountSid = os.getenv("TWILIO_ACCOUNT_SID")
authToken = os.getenv("TWILIO_AUTH_TOKEN")
# Import the Twilio SDK
from twilio.rest import Client
from twilio.twiml.messaging_response import MessagingResponse
# Instantiate a Twilio Client using the accountSid and authToken
twilioClient = Client(accountSid, authToken)
The code reviewed thus far will execute when the Django app is loaded by the web server. Next, declare a function to handle requests. You will configure Twilio to invoke this function each time your Twilio-owned number receives an SMS. The function’s response and actions taken will be determined by the contents of the object passed in as the request
parameter.
@require_POST
@csrf_exempt
def index(request):
print(f"Event: {request.POST}")
# Define a response object, in case a response to the sender is required
resp = MessagingResponse()
Before invoking the Audit Service, determine if the inbound message should be added to the secure audit log and if so who to relay the message to after it is logged. Only messages between the two numbers configured in the .env file should be logged. Determine the destinationNumber
to relay the message to.
- If the message originated from the owner, send it to the target.
- If the message came from the target, send it to the owner.
- If the message came from any other number, notify the sender that the message will be ignored by populating and returning the
MessageResponse
.
# Determine the destination number
if request.POST['From'].endswith(ownerNumber):
# If the message is from the owner, send it to target
destinationNumber = targetNumber
elif request.POST['From'].endswith(targetNumber):
# If the message is form the target, send it to owner
destinationNumber = ownerNumber
else:
# If the message is from any other number, reply to the sender
resp.message("AUTOMATED RESPONSE: This is a private communication channel to securely record auditable conversations. Your message will be ignored!")
return HttpResponse(resp)
Create an audit Event
object and map the relevant details to the log entry. Set the actor
field to the Twilio-owned number that is logging and forwarding the message. The source
is set to the number that sent the incoming SMS, read from the requests From
field, and target
is set to the intended recipient or destinationNumber
. The message
is set to the body or contents of the SMS, also read from the incoming request.
# The number the original message was sent to is the number of the proxy
proxyNumber = request.POST['To'];
# The message originally sent to the poxy.
originalMessage = request.POST['Body']
# Map the Twilio event details to the Pangea Event object, for example, the
# source is set to the number that sent the message and the target is the
# recipient.
auditData = Event(
actor=proxyNumber,
source=request.POST['From'],
target=destinationNumber,
message=originalMessage,
status=request.POST['SmsStatus'],
action="forwarded",
)
Call the log
method of the auditService
with the auditData
. This will invoke the Pangea Service to create the log entry. The hash of the message will also be recorded on a tamper-proof blockchain which can then be used to prove the conversation has not been modified. You can explore the log viewer on the Pangea Console to verify the message integrity later.
NOTE: The
verbose
parameter is set totrue
. This will instruct the Audit service to return a detailed response. You will need the details returned to determine if the logged message was modified by the Redact Rulesets.
try:
auditResponse = auditService.log(event=auditData, verbose=True)
print(f"Response: {auditResponse.result.dict(exclude_none=True)}")
The log
function returns an auditResponse
. If the response is marked successful, read the logged and potentially modified message from the response and use the twilioClient
to relay the contents of the message to the destinationNumber
.
if auditResponse.success:
print(f"Forwarding message to: {destinationNumber}")
loggedMessage = auditResponse.result.envelope.event.message
# Send the logged message to the destinationNumber
twilioResponse = twilioClient.messages.create(
body=loggedMessage,
from_=proxyNumber,
to=destinationNumber
)
if twilioResponse.error_code is None:
print("SMS successfully sent")
If the originalMessage
received by the proxy is different than the loggedMessage
returned by the Audit service, notify the sender that the message was modified before sending it to the recipient, by populating a message to the MessagingResponse
represented by the twiml
variable. Otherwise, the twilml
will be returned with a blank response when the function completes.
# If the logged message was modified by the redact rule set,
# notify the sender via an automated response
if loggedMessage != originalMessage:
print("Redact detected")
resp.message("AUTOMATED RESPONSE: You sent a message with sensitive, personal information. Our system redacted that information so that you can remain protected. The recipient of that message cannot access your sensitive information through this conversation.")
Run the app
Django projects are bundled with the command-line utility, manage.py, to help you interact with your project. Use the following command to start a development server on you local machine:
python3 manage.py runserver 3000
You’ll see the following output on the command line:
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
September 29, 2022 - 19:24:04
Django version 4.1.1, using settings 'audit_proxy.settings'
Starting development server at http://127.0.0.1:3000/
Quit the server with CONTROL-C
Your web app is now running! Your function is waiting to respond to requests sent to http://127.0.0.1:3000/audit/ but this URL is only reachable from your local computer. You’ll need to make the endpoint accessible publicly so Twilio can query it when an SMS is received.
Make your app accessible publicly on the internet with ngrok
Twilio and other web services use the webhook callback pattern for event-driven interaction between two services on the Internet, in this case, Twilio and your web application. The ngrok program exposes services running locally on your machine via a url accessible from anywhere on the internet. Visit the link for details or follow these quick instructions to get started quickly:
-
Download the version for your particular system and install it to a location of your choice.
-
Using the terminal, navigate the folder you installed it to.
-
Run the following command to start ngrok and tell it which port to expose to the public internet.
On Linux and Mac:
./ngrok http 3000
Or on Windows:
ngrok http 3000
You should see the following output on the command line:
ngrok (Ctrl+C to quit)
Visit http://localhost:4040/ to inspect, replay, and modify your requests
Session Status online
Account your name (Plan: Free)
Version 3.1.0
Region United States (us)
Latency 99ms
Web Interface http://127.0.0.1:4040
Forwarding https://4762-47-156-19-205.ngrok.io -> http://localhost:3000
Make a note of the Forwarding base URL above. It will be needed to configure your Twilio programmable number to query your app for instruction when an SMS is received.
Configure Twilio webhooks
If you do not already have a Twilio number follow these instructions:
- Go to your Phone Numbers Dashboard .
- Click Buy a Number.
- Search for a number that suits you.
- Click Buy
- Confirm your purchase, then click Setup Number.
Otherwise, navigate to the Active numbers panel of the Twilio console and select the number you’d like to use with this service.
Under Messaging, look for the line that says A message comes in. Change the first box to Webhook and add the ngrok base URL with the path to the audit/ endpoint appended to it in the second box. Yours should look similar to https://[your generated ID].ngrok.io/audit
. Save the configuration. The function on your local machine will now be invoked every time an SMS is sent to this number.
Congratulations! You just configured a Pangea-enabled Twilio service. You now have a secure audit trail between the OWNER_NUMBER
and TARGET_NUMBER
you configured in the .env file. Use a cellphone with either number to send an SMS to the Twilio number you configured to invoke your function. The SMS message will be logged by the Pangea service and forwarded to the other participant, similarly, their replies will be forwarded back to you creating a conversation thread on the SMS apps on both your phones.
To later view the conversation or present the verified proof that messages were not altered or deleted, navigate back to the Pangea Console , select Secure Audit Log from the left-hand navigation menu, and then select View Logs.
You can expand each message to view the sender and recipient details, labeled as source and target, respectively.
The green lock to the left of each message indicates that its hash has been published to the ARWeave blockchain and verified. To view the transaction on ViewBlock.io , click the lock icon and then click the View button next to Published Root.
NOTE: Publishing occurs once per hour so it may take up to an hour for a record to show as Verified.
Configure Redact rules
You can configure the Audit service to redact specific data formats, such as emails, credit card numbers, and other sensitive or personal information. To do so, select Settings from the left-hand navigation menu, and then select Redact records.
If you have not yet enabled the Redact service, you will be presented with the Enable Redact Service option on the right-hand side. Click the Configure Redact button and review the benefits of the service. Then, click Next to continue.
Provide a new Token name, then select both Secure Audit Log and Redact from the Or choose from the list of individual services below section, and click Done.
From the Redact Overview dashboard, make a note of the TOKEN you just created and notice that both Redact and Audit are listed in the ACCESS RIGHTS column.
NOTE: You can quickly copy the token to your system's clipboard using the shortcut.
Select Rulesets from the left-hand menu, to configure which types of data are redacted from log entries. Then, to redact email addresses and names, for example, select PII and enable the switches in the EMAIL_ADDRESS and PERSON sections. Then, click Save to update the rulesets.
Using the left-hand navigation menu, navigate back to Secure Audit Log > Setting. Select Redact records from the left column and enable the switch for Redact records. Then, click Save to update the settings change.
Update the token environment variable
Your app must now provide the Pangea Audit SDK the new token with access rights to both the Audit and Redact service. To do so, update the PANGEA_AUTH_TOKEN
value in the .env file and restart the app.
Restart the app
- Open the terminal window that is running the app and use CONTROL+C to terminate the web server.
- When the command prompt reappears, use the following command to restart the server:
python3 manage.py runserver 3000
The app will now use the updated token to communicate with the Audit service.
Test the Redact rules
Try sending a message that contains a name or email address, something like:
Hi, my name is Nicolas Vautier and my email is nicolas.vautier@pangea.cloud
You will receive an automated response each time a message is modified by the Redact service and the recipient will receive the modified message.
You can now update the Redact Settings from the Pangea Console at any time without redeploying the app. The redact rules will be applied to each new message sent through the proxy.
Conclusion
In this article, you learned how to build and deploy an SMS proxy that records conversations and provides users with verifiable proof that the conversation was not altered. Most telecom providers maintain records of the messages sent over their network, but even the largest carriers are susceptible to tampered records on their centralized data sources. It may also be impractical for your users to request conversation logs from carriers as the process may require a legal process or subpoena. Utilizing a Blockchain with your Pangea-powered proxy you can quickly solve both these problems for your user.
Resources
- Secure Audit Log Overview
- Redact Overview