SlideShare a Scribd company logo
JSON SQL Injection 
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. 
and 
the Lessons Learned 
DeNA Co., Ltd. 
Kazuho Oku 
1
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. 
Who am I? 
 Field: 
⁃ network and web-related architecture 
 Works: 
⁃ Palmscape / Xiino (web browser for Palm OS) 
⁃ Author of various Perl modules 
• Class::Accessor::Lite, HTTP::Parser::XS, 
Parallel::Prefork, Server::Starter, Starlet, 
Test::Mysqld, ... 
⁃ Author of various MySQL extensions 
• Q4M, mycached, ... 
⁃ Also the author of: 
• JSX, picojson, ... 
2
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. 
Agenda 
 What is an SQL Query Builder? 
 JSON SQL Injection 
 SQL::QueryMaker and strict mode of SQL::Maker 
 The Lessons Learned 
3
What is an SQL Query Builder? 
4 
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. 
What is an SQL Query Builder? 
 is a library for building SQL queries 
⁃ exists below or as a part of an object-relational 
mapping library (ORM) 
• ORM understands the semantics of the database 
schema / query builder does not 
5 
Application 
ORM Library 
SQL Query Builder 
Database API (DBI) 
Database Driver (DBD)
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. 
Popular Implementations 
 SQL::Abstract 
 SQL::Interp 
 SQL::Maker 
⁃ used by Teng 
⁃ is today's main focus 
6 
Application 
ORM Library 
SQL Query Builder 
Database API (DBI) 
Database Driver (DBD)
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. 
Query Builders are Great! 
 Easy to build query conditions 
⁃ by using hashrefs and arrayrefs 
⁃ arrayref is considered as IN queries 
• e.g. foo => [1,2,3] becomes `foo` IN (1,2,3) 
⁃ hashref is considered as (operator, value) pair 
• e.g. foo => { '<', 30 } becomes `foo`<30 
⁃ the API is common to the aforementioned query 
builders 
7
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. 
Examples 
use SQL::Maker; 
... 
$maker->select('user', '*', { name => 'tokuhirom' }); 
# => SELECT * FROM `user` WHERE `name`='tokuhirom'; 
$maker->select('user', '*', { name => [ 'tokuhirom', 'yappo' ] }); 
# => SELECT * FROM `user` WHERE `name` IN ('tokuhirom','yappo'); 
$maker->select('user', '*', { age => { '>' => 30 } }); 
# => SELECT * FROM `user` WHERE `age`>30; 
$maker->delete('user', { name => 'sugyan' }); 
# => DELETE FROM `user` WHERE `name`='sugyan'; 
8
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. 
Examples (cont’d) 
use SQL::Maker; 
... 
$maker->select('user', '*', { name => [ 'tokuhirom', 'yappo' ] }); 
# => SELECT * FROM `user` WHERE `name` IN ('tokuhirom','yappo'); 
$maker->select('user', '*', { name => [] }); 
# => SELECT * FROM `user` WHERE 1=0; 
$maker->select('user', '*', { 
age => 30, 
sex => 0, # male 
}); 
# => SELECT * FROM `user` WHERE `age`=30 AND `sex`=0; 
9
So What is JSON SQL Injection? 
10 
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. 
The Problem 
 User-supplied input might not be the expected type 
# this API returns the entries of a blog (specified by $json->{blog_id}) 
my $json = decode_json($input); 
my ($sql, @binds) = $maker->select( 
'blog_entries', '*', { id => $json->{blog_id} }); 
my $rows = $dbi->selectall_arrayref($sql, { Slice => {} }, @binds); 
send_output_as_json([ map { +{ 
entry_id => $_->{id}, 
entry_title => $_->{title}, 
} } @$rows ]); 
11 
What if $json->{name} was not a scalar?
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. 
The Problem (cont’d) 
 Will return a list of all blog entries if the supplied 
JSON was: { "blog_id": { "!=": -1 } } 
# this API returns the entries of a blog (specified by $json->{blog_id}) 
my $json = decode_json($input); 
# generated query: SELECT * FROM `blog_entries` WHERE `id`!=-1 
my ($sql, @binds) = $maker->select( 
'blog_entries', '*', { id => $json->{blog_id} }); 
my $rows = $dbi->selectall_arrayref($sql, { Slice => {} }, @binds); 
send_output_as_json([ map { +{ 
entry_id => $_->{id}, 
entry_title => $_->{title}, 
} } @$rows ]); 
12
Can it be used as an attack vector? 
13 
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. 
Yes 
14
Information Leakage in a Twitter-like App. 
# this API returns the tweets of a user specified by $json->{user_id}, who is following the authenticating user 
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. 
if (! is_following($session->{user_id}, $json->{user_id})) { 
return "cannot return the tweets of an user who is not following you"; 
} 
my ($sql, @binds) = $maker->select('tweet', '*', { user => $json->{user_id} }); 
My $rows = $dbi->selectall_arrayref($sql, { Slice => {} }, @binds); 
send_output_as_json([ map { ... } @$rows ]); 
sub is_following { 
my ($user, $following) = @_; 
# builds query: SELECT * FROM following WHERE user=$user AND following=$following 
my ($sql, @binds) = $maker->select( 
'following', '*', { user => $user, following => $following }); 
my $rows = $dbi->selectall_arrayref($sql, @binds); 
return @$rows != 0; 
} 
15
Information Leakage in a Twitter-like App. 
(cont'd) 
# in case the JSON is: { user_id: { "!=": -1 } } 
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. 
if (! is_following($session->{user_id}, $json->{user_id})) { 
return "cannot return the tweets of an user who is not following you"; 
} 
# generated query is SELECT * FROM `tweet` WHERE `user`!=-1, returns tweets of all users 
my ($sql, @binds) = $maker->select('tweet', '*', { user => $json->{user_id} }); 
My $rows = $dbi->selectall_arrayref($sql, { Slice => {} }, @binds); 
send_output_as_json([ map { ... } @$rows ]); 
sub is_following { 
my ($user, $following) = @_; 
# the generated query becomes like bellow and the function likely returns TRUE: 
# SELECT * FROM `following` WHERE `user`=$user AND `following`!=-1 
my ($sql, @binds) = $maker->select( 
'following', '*', { user => $user, following => $following }); 
my $rows = $dbi->selectall_arrayref($sql, @binds); 
return @$rows != 0; 
} 
16
Is the problem in the SQL query builders 
using hash for injecting arbitrary operators? 
17 
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. 
No 
18
Handling of Array is problematic as well 
# in case the JSON is: { user_id: [ 12, 34 ] }, returns tweets of both users if either is following the authenticating 
user 
if (! is_following($session->{user_id}, $json->{user_id})) { 
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. 
return "cannot return the tweets of an user who is not following you"; 
} 
# generates: SELECT * FROM `tweet` WHERE `user` IN (12,34) 
my ($sql, @binds) = $maker->select('tweet', '*', { user => $json->{user_id} }); 
My $rows = $dbi->selectall_arrayref($sql, { Slice => {} }, @binds); 
send_output_as_json([ map { ... } @$rows ]); 
sub is_following { 
my ($user, $following) = @_; 
# generates: SELECT * FROM `following` WHERE `user`=$user AND `following` IN (12,34) 
my ($sql, @binds) = $maker->select( 
'following', '*', { user => $user, following => $following }); 
my $rows = $dbi->selectall_arrayref($sql, @binds); 
return @$rows != 0; 
} 
19
Does the same problem exist in web 
application frameworks written in 
programming languages other than Perl? 
20 
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. 
Yes. 
Many web application frameworks (e.g. Ruby 
on Rails) automatically convert condition 
specified by an array into an IN query. 
21
Is the problem only related to the handling 
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. 
of JSON? 
22
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. 
Yes & No 
23
Query decoders may return nested data 
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. 
 in case of PHP and Ruby on Rails 
query?id=1 => { id: 1 } 
query?id[]=1&id[]=2 => { id: [1, 2] } 
query?user[name]=yappo => { user: { name: "yappo" } } 
⁃ also when using Data::NestedParams in Perl 
 Catalyst switches from scalars to using arrayrefs 
when the property is defined more than once 
query?id=1 => { id => 1 } 
query?id=1&id=2 => { id => [1, 2] } 
 not the case for CGI.pm and Plack 
24
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. 
SQL::QueryMaker 
and 
the strict mode of SQL::Maker 
25
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. 
Overview of SQL::QueryMaker 
 Provides a fail-safe API 
⁃ provides functions to specify the SQL operators; 
that return blessed refs to represent them 
(instead of using arrayrefs / hashrefs) 
sql_eq(name => 'yappo') # `name`='yappo' 
sql_in(id => [ 123, 456 ]) # `id` IN (123,456) 
sql_and([ # `sex`=1 AND `age`<=30 
sex => 1, # female 
age => sql_ge(30), 
]) 
 Added strict mode to SQL::Maker 
⁃ raises error when arrayref / hashref is given as a 
condition 
26
The snippet becomes safe in strict mode 
# this API returns the tweets of a user specified by $json->{user_id}, who is following the authenticating user 
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. 
my $maker = SQL::Maker->new(..., strict => 1); 
if (! is_following($session->{user_id}, $json->{user_id})) { 
return "cannot return the tweets of an user who is not following you"; 
} 
# in strict mode, SQL::Maker raises an error if $json->{user_id} is not a scalar 
my ($sql, @binds) = $maker->select('tweet', '*', { user => $json->{user_id} }); 
My $rows = $dbi->selectall_arrayref($sql, { Slice => {} }, @binds); 
send_output_as_json([ map { ... } @$rows ]); 
sub is_following { 
my ($user, $following) = @_; 
# ditto as above 
my ($sql, @binds) = $maker->select( 
'following', '*', { user => $user, following => $following }); 
my $rows = $dbi->selectall_arrayref($sql, @binds); 
return @$rows != 0; 
} 
27
Existing code may not work under strict mode 
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. 
my $maker = SQL::Maker->new(..., strict => 1); 
# equality comparison works as is 
$maker->select(..., { foo => 123 }); 
# non-equality comparison needs to be rewritten 
$maker->select(..., { foo => [ 123, 456 ]); 
=> $maker->select(..., { foo => sql_in([ 123, 456 ]) }); 
$maker->select(..., { foo => { '<' => 30 } }); 
=> $maker->select(..., { foo => sql_lt(30) }); 
28
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. 
Supported in Teng >= 0.24 
my $teng = My::DB->new({ 
..., 
sql_builder_args => { 
strict => 1, 
} 
,}); 
29
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. 
The Lessons Learned 
30
Always validate the type of the input 
 do not forget to validate the type of the input 
⁃ even if you do not need to check the value of 
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. 
the input 
 checks can be done either within the Controller or 
within the Model (in case of SQL::Maker) 
⁃ validation in the Controller is preferable 
31
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. 
Write fail-safe code 
 do not change the behavior based on the type of 
the input 
⁃ instead, provide different method for each type 
of the input 
⁃ e.g. sql_eq vs. sql_in 
32
Use blessed refs for dynamic behavior 
 use blessed refs in case you need to change the 
behavior based on the type of the input 
⁃ this is a common idiom; many template engines 
use blessed refs to determine whether if a string 
is already HTML-escaped 
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. 
# in case of Text::MicroTemplate 
sub escape_html { 
my $str = shift; 
return '' 
unless defined $str; 
return $str->as_string 
if ref $str eq 'Text::MicroTemplate::EncodedString'; 
$str =~ s/([&><"'])/$_escape_table{$1}/ge; 
return $str; 
} 
33
Use blessed refs for dynamic behavior (cont'd) 
 do not use serialization libraries with support for 
blessed objects (e.g. YAML or Storable) for user 
input 
⁃ such use may lead to XSS or other code 
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. 
injection vulnerability 
⁃ always only accept scalars / arrays / hashes and 
validate their type and value 
34
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. 
Thanks to 
 Toshiharu Sugiyama 
⁃ original reporter of the issue 
⁃ http://developers.mobage.jp/blog/2014/7/3/jsonsql-injection 
 @tokuhirom, @cho45 
⁃ for coordinating / working on the fix 
 @miyagawa 
⁃ for the behavior of Catalyst, Ruby, etc. 
 @ockeghem 
⁃ for looking into other impl. sharing the problem 
⁃ http://blog.tokumaru.org/2014/07/json-sql-injectionphpjson. 
html 
35

More Related Content

PDF
DOAG Oracle Unified Audit in Multitenant Environments
PDF
Automation with ansible
PDF
Step by Step Restore rman to different host
PDF
Advanced SQL injection to operating system full control (whitepaper)
PDF
Create Directory Under ASM Diskgroup
PPTX
Introduce AWS Lambda for newbie and Non-IT
PPTX
Introduction to Gitlab | Gitlab 101 | Training Session
PPTX
BTRisk Zararlı Yazılım Analizi Eğitimi Sunumu - Bölüm 1
DOAG Oracle Unified Audit in Multitenant Environments
Automation with ansible
Step by Step Restore rman to different host
Advanced SQL injection to operating system full control (whitepaper)
Create Directory Under ASM Diskgroup
Introduce AWS Lambda for newbie and Non-IT
Introduction to Gitlab | Gitlab 101 | Training Session
BTRisk Zararlı Yazılım Analizi Eğitimi Sunumu - Bölüm 1

What's hot (20)

PPTX
Journey of saga pattern in microservice architecture
PDF
Azure Penetration Testing
PDF
Real-Time Query for Data Guard
PDF
İleri Seviye Ağ Güvenliği Lab Kitabı
PDF
Uygulamalı Ağ Güvenliği Eğitimi Lab Çalışmaları
ODP
ansible why ?
PPTX
Mulesoft Connections to different companies, and different services
PDF
High Performance PL/SQL
PPTX
Camunda BPM 7.13 Webinar
PPTX
Docker Container Security
PPTX
Fast Start Failover DataGuard
PPTX
BPM Patterns & Best Practices with OutSystems BPT
PDF
Gitlab ci-cd
PDF
Pentest with Metasploit
PPTX
RACE - Minimal Rights and ACE for Active Directory Dominance
PPT
Docker introduction
PPTX
Microservices With Istio Service Mesh
PPTX
Symbian OS - Platform Security
PDF
Event-Driven Architecture (EDA)
PPTX
Golismero
Journey of saga pattern in microservice architecture
Azure Penetration Testing
Real-Time Query for Data Guard
İleri Seviye Ağ Güvenliği Lab Kitabı
Uygulamalı Ağ Güvenliği Eğitimi Lab Çalışmaları
ansible why ?
Mulesoft Connections to different companies, and different services
High Performance PL/SQL
Camunda BPM 7.13 Webinar
Docker Container Security
Fast Start Failover DataGuard
BPM Patterns & Best Practices with OutSystems BPT
Gitlab ci-cd
Pentest with Metasploit
RACE - Minimal Rights and ACE for Active Directory Dominance
Docker introduction
Microservices With Istio Service Mesh
Symbian OS - Platform Security
Event-Driven Architecture (EDA)
Golismero
Ad

Similar to JSON SQL Injection and the Lessons Learned (20)

PDF
Create a res tful services api in php.
PPT
Going crazy with Node.JS and CakePHP
PDF
Introduction to Active Record at MySQL Conference 2007
PDF
Building Web-API without Rails, Registration or SMS
PDF
SproutCore and the Future of Web Apps
KEY
Zend Framework Study@Tokyo #2
PDF
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
PPTX
Web Security - Hands-on
PDF
Charla EHU Noviembre 2014 - Desarrollo Web
PDF
Data models in Angular 1 & 2
PDF
Introduction to Active Record - Silicon Valley Ruby Conference 2007
KEY
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
PDF
Bag Of Tricks From Iusethis
PDF
Using Sinatra to Build REST APIs in Ruby
PDF
Doctrine For Beginners
ODP
Top 10 Web Security Vulnerabilities
PDF
Android networking-2
PDF
RESTful web services
PDF
Kicking off with Zend Expressive and Doctrine ORM (Sunshine PHP 2017)
PPTX
Laravel Security Standards
Create a res tful services api in php.
Going crazy with Node.JS and CakePHP
Introduction to Active Record at MySQL Conference 2007
Building Web-API without Rails, Registration or SMS
SproutCore and the Future of Web Apps
Zend Framework Study@Tokyo #2
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
Web Security - Hands-on
Charla EHU Noviembre 2014 - Desarrollo Web
Data models in Angular 1 & 2
Introduction to Active Record - Silicon Valley Ruby Conference 2007
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Bag Of Tricks From Iusethis
Using Sinatra to Build REST APIs in Ruby
Doctrine For Beginners
Top 10 Web Security Vulnerabilities
Android networking-2
RESTful web services
Kicking off with Zend Expressive and Doctrine ORM (Sunshine PHP 2017)
Laravel Security Standards
Ad

More from Kazuho Oku (20)

PDF
HTTP/2で 速くなるとき ならないとき
PDF
QUIC標準化動向 〜2017/7
PDF
HTTP/2の課題と将来
PDF
TLS 1.3 と 0-RTT のこわ〜い話
PDF
Reorganizing Website Architecture for HTTP/2 and Beyond
PPTX
Recent Advances in HTTP, controlling them using ruby
PPTX
Programming TCP for responsiveness
PDF
Programming TCP for responsiveness
PDF
Developing the fastest HTTP/2 server
PPTX
TLS & LURK @ IETF 95
PPTX
HTTPとサーバ技術の最新動向
PPTX
ウェブを速くするためにDeNAがやっていること - HTTP/2と、さらにその先
PPTX
Cache aware-server-push in H2O version 1.5
PDF
HTTP/2時代のウェブサイト設計
PDF
H2O - making the Web faster
PDF
H2O - making HTTP better
PDF
H2O - the optimized HTTP server
PPTX
JSX 速さの秘密 - 高速なJavaScriptを書く方法
PPTX
JSX の現在と未来 - Oct 26 2013
PPTX
Using the Power to Prove
HTTP/2で 速くなるとき ならないとき
QUIC標準化動向 〜2017/7
HTTP/2の課題と将来
TLS 1.3 と 0-RTT のこわ〜い話
Reorganizing Website Architecture for HTTP/2 and Beyond
Recent Advances in HTTP, controlling them using ruby
Programming TCP for responsiveness
Programming TCP for responsiveness
Developing the fastest HTTP/2 server
TLS & LURK @ IETF 95
HTTPとサーバ技術の最新動向
ウェブを速くするためにDeNAがやっていること - HTTP/2と、さらにその先
Cache aware-server-push in H2O version 1.5
HTTP/2時代のウェブサイト設計
H2O - making the Web faster
H2O - making HTTP better
H2O - the optimized HTTP server
JSX 速さの秘密 - 高速なJavaScriptを書く方法
JSX の現在と未来 - Oct 26 2013
Using the Power to Prove

Recently uploaded (20)

PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PPTX
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PDF
Approach and Philosophy of On baking technology
PDF
Electronic commerce courselecture one. Pdf
PPT
Teaching material agriculture food technology
PDF
CIFDAQ's Market Insight: SEC Turns Pro Crypto
PPTX
Understanding_Digital_Forensics_Presentation.pptx
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PDF
Unlocking AI with Model Context Protocol (MCP)
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
DOCX
The AUB Centre for AI in Media Proposal.docx
PDF
Bridging biosciences and deep learning for revolutionary discoveries: a compr...
PDF
Review of recent advances in non-invasive hemoglobin estimation
PDF
NewMind AI Monthly Chronicles - July 2025
PPTX
MYSQL Presentation for SQL database connectivity
PPTX
Big Data Technologies - Introduction.pptx
Mobile App Security Testing_ A Comprehensive Guide.pdf
Diabetes mellitus diagnosis method based random forest with bat algorithm
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
Per capita expenditure prediction using model stacking based on satellite ima...
Approach and Philosophy of On baking technology
Electronic commerce courselecture one. Pdf
Teaching material agriculture food technology
CIFDAQ's Market Insight: SEC Turns Pro Crypto
Understanding_Digital_Forensics_Presentation.pptx
Reach Out and Touch Someone: Haptics and Empathic Computing
Unlocking AI with Model Context Protocol (MCP)
Chapter 3 Spatial Domain Image Processing.pdf
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
The AUB Centre for AI in Media Proposal.docx
Bridging biosciences and deep learning for revolutionary discoveries: a compr...
Review of recent advances in non-invasive hemoglobin estimation
NewMind AI Monthly Chronicles - July 2025
MYSQL Presentation for SQL database connectivity
Big Data Technologies - Introduction.pptx

JSON SQL Injection and the Lessons Learned

  • 1. JSON SQL Injection Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. and the Lessons Learned DeNA Co., Ltd. Kazuho Oku 1
  • 2. Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. Who am I?  Field: ⁃ network and web-related architecture  Works: ⁃ Palmscape / Xiino (web browser for Palm OS) ⁃ Author of various Perl modules • Class::Accessor::Lite, HTTP::Parser::XS, Parallel::Prefork, Server::Starter, Starlet, Test::Mysqld, ... ⁃ Author of various MySQL extensions • Q4M, mycached, ... ⁃ Also the author of: • JSX, picojson, ... 2
  • 3. Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. Agenda  What is an SQL Query Builder?  JSON SQL Injection  SQL::QueryMaker and strict mode of SQL::Maker  The Lessons Learned 3
  • 4. What is an SQL Query Builder? 4 Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.
  • 5. Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. What is an SQL Query Builder?  is a library for building SQL queries ⁃ exists below or as a part of an object-relational mapping library (ORM) • ORM understands the semantics of the database schema / query builder does not 5 Application ORM Library SQL Query Builder Database API (DBI) Database Driver (DBD)
  • 6. Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. Popular Implementations  SQL::Abstract  SQL::Interp  SQL::Maker ⁃ used by Teng ⁃ is today's main focus 6 Application ORM Library SQL Query Builder Database API (DBI) Database Driver (DBD)
  • 7. Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. Query Builders are Great!  Easy to build query conditions ⁃ by using hashrefs and arrayrefs ⁃ arrayref is considered as IN queries • e.g. foo => [1,2,3] becomes `foo` IN (1,2,3) ⁃ hashref is considered as (operator, value) pair • e.g. foo => { '<', 30 } becomes `foo`<30 ⁃ the API is common to the aforementioned query builders 7
  • 8. Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. Examples use SQL::Maker; ... $maker->select('user', '*', { name => 'tokuhirom' }); # => SELECT * FROM `user` WHERE `name`='tokuhirom'; $maker->select('user', '*', { name => [ 'tokuhirom', 'yappo' ] }); # => SELECT * FROM `user` WHERE `name` IN ('tokuhirom','yappo'); $maker->select('user', '*', { age => { '>' => 30 } }); # => SELECT * FROM `user` WHERE `age`>30; $maker->delete('user', { name => 'sugyan' }); # => DELETE FROM `user` WHERE `name`='sugyan'; 8
  • 9. Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. Examples (cont’d) use SQL::Maker; ... $maker->select('user', '*', { name => [ 'tokuhirom', 'yappo' ] }); # => SELECT * FROM `user` WHERE `name` IN ('tokuhirom','yappo'); $maker->select('user', '*', { name => [] }); # => SELECT * FROM `user` WHERE 1=0; $maker->select('user', '*', { age => 30, sex => 0, # male }); # => SELECT * FROM `user` WHERE `age`=30 AND `sex`=0; 9
  • 10. So What is JSON SQL Injection? 10 Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.
  • 11. Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. The Problem  User-supplied input might not be the expected type # this API returns the entries of a blog (specified by $json->{blog_id}) my $json = decode_json($input); my ($sql, @binds) = $maker->select( 'blog_entries', '*', { id => $json->{blog_id} }); my $rows = $dbi->selectall_arrayref($sql, { Slice => {} }, @binds); send_output_as_json([ map { +{ entry_id => $_->{id}, entry_title => $_->{title}, } } @$rows ]); 11 What if $json->{name} was not a scalar?
  • 12. Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. The Problem (cont’d)  Will return a list of all blog entries if the supplied JSON was: { "blog_id": { "!=": -1 } } # this API returns the entries of a blog (specified by $json->{blog_id}) my $json = decode_json($input); # generated query: SELECT * FROM `blog_entries` WHERE `id`!=-1 my ($sql, @binds) = $maker->select( 'blog_entries', '*', { id => $json->{blog_id} }); my $rows = $dbi->selectall_arrayref($sql, { Slice => {} }, @binds); send_output_as_json([ map { +{ entry_id => $_->{id}, entry_title => $_->{title}, } } @$rows ]); 12
  • 13. Can it be used as an attack vector? 13 Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.
  • 14. Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. Yes 14
  • 15. Information Leakage in a Twitter-like App. # this API returns the tweets of a user specified by $json->{user_id}, who is following the authenticating user Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. if (! is_following($session->{user_id}, $json->{user_id})) { return "cannot return the tweets of an user who is not following you"; } my ($sql, @binds) = $maker->select('tweet', '*', { user => $json->{user_id} }); My $rows = $dbi->selectall_arrayref($sql, { Slice => {} }, @binds); send_output_as_json([ map { ... } @$rows ]); sub is_following { my ($user, $following) = @_; # builds query: SELECT * FROM following WHERE user=$user AND following=$following my ($sql, @binds) = $maker->select( 'following', '*', { user => $user, following => $following }); my $rows = $dbi->selectall_arrayref($sql, @binds); return @$rows != 0; } 15
  • 16. Information Leakage in a Twitter-like App. (cont'd) # in case the JSON is: { user_id: { "!=": -1 } } Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. if (! is_following($session->{user_id}, $json->{user_id})) { return "cannot return the tweets of an user who is not following you"; } # generated query is SELECT * FROM `tweet` WHERE `user`!=-1, returns tweets of all users my ($sql, @binds) = $maker->select('tweet', '*', { user => $json->{user_id} }); My $rows = $dbi->selectall_arrayref($sql, { Slice => {} }, @binds); send_output_as_json([ map { ... } @$rows ]); sub is_following { my ($user, $following) = @_; # the generated query becomes like bellow and the function likely returns TRUE: # SELECT * FROM `following` WHERE `user`=$user AND `following`!=-1 my ($sql, @binds) = $maker->select( 'following', '*', { user => $user, following => $following }); my $rows = $dbi->selectall_arrayref($sql, @binds); return @$rows != 0; } 16
  • 17. Is the problem in the SQL query builders using hash for injecting arbitrary operators? 17 Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.
  • 18. Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. No 18
  • 19. Handling of Array is problematic as well # in case the JSON is: { user_id: [ 12, 34 ] }, returns tweets of both users if either is following the authenticating user if (! is_following($session->{user_id}, $json->{user_id})) { Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. return "cannot return the tweets of an user who is not following you"; } # generates: SELECT * FROM `tweet` WHERE `user` IN (12,34) my ($sql, @binds) = $maker->select('tweet', '*', { user => $json->{user_id} }); My $rows = $dbi->selectall_arrayref($sql, { Slice => {} }, @binds); send_output_as_json([ map { ... } @$rows ]); sub is_following { my ($user, $following) = @_; # generates: SELECT * FROM `following` WHERE `user`=$user AND `following` IN (12,34) my ($sql, @binds) = $maker->select( 'following', '*', { user => $user, following => $following }); my $rows = $dbi->selectall_arrayref($sql, @binds); return @$rows != 0; } 19
  • 20. Does the same problem exist in web application frameworks written in programming languages other than Perl? 20 Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.
  • 21. Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. Yes. Many web application frameworks (e.g. Ruby on Rails) automatically convert condition specified by an array into an IN query. 21
  • 22. Is the problem only related to the handling Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. of JSON? 22
  • 23. Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. Yes & No 23
  • 24. Query decoders may return nested data Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.  in case of PHP and Ruby on Rails query?id=1 => { id: 1 } query?id[]=1&id[]=2 => { id: [1, 2] } query?user[name]=yappo => { user: { name: "yappo" } } ⁃ also when using Data::NestedParams in Perl  Catalyst switches from scalars to using arrayrefs when the property is defined more than once query?id=1 => { id => 1 } query?id=1&id=2 => { id => [1, 2] }  not the case for CGI.pm and Plack 24
  • 25. Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. SQL::QueryMaker and the strict mode of SQL::Maker 25
  • 26. Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. Overview of SQL::QueryMaker  Provides a fail-safe API ⁃ provides functions to specify the SQL operators; that return blessed refs to represent them (instead of using arrayrefs / hashrefs) sql_eq(name => 'yappo') # `name`='yappo' sql_in(id => [ 123, 456 ]) # `id` IN (123,456) sql_and([ # `sex`=1 AND `age`<=30 sex => 1, # female age => sql_ge(30), ])  Added strict mode to SQL::Maker ⁃ raises error when arrayref / hashref is given as a condition 26
  • 27. The snippet becomes safe in strict mode # this API returns the tweets of a user specified by $json->{user_id}, who is following the authenticating user Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. my $maker = SQL::Maker->new(..., strict => 1); if (! is_following($session->{user_id}, $json->{user_id})) { return "cannot return the tweets of an user who is not following you"; } # in strict mode, SQL::Maker raises an error if $json->{user_id} is not a scalar my ($sql, @binds) = $maker->select('tweet', '*', { user => $json->{user_id} }); My $rows = $dbi->selectall_arrayref($sql, { Slice => {} }, @binds); send_output_as_json([ map { ... } @$rows ]); sub is_following { my ($user, $following) = @_; # ditto as above my ($sql, @binds) = $maker->select( 'following', '*', { user => $user, following => $following }); my $rows = $dbi->selectall_arrayref($sql, @binds); return @$rows != 0; } 27
  • 28. Existing code may not work under strict mode Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. my $maker = SQL::Maker->new(..., strict => 1); # equality comparison works as is $maker->select(..., { foo => 123 }); # non-equality comparison needs to be rewritten $maker->select(..., { foo => [ 123, 456 ]); => $maker->select(..., { foo => sql_in([ 123, 456 ]) }); $maker->select(..., { foo => { '<' => 30 } }); => $maker->select(..., { foo => sql_lt(30) }); 28
  • 29. Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. Supported in Teng >= 0.24 my $teng = My::DB->new({ ..., sql_builder_args => { strict => 1, } ,}); 29
  • 30. Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. The Lessons Learned 30
  • 31. Always validate the type of the input  do not forget to validate the type of the input ⁃ even if you do not need to check the value of Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. the input  checks can be done either within the Controller or within the Model (in case of SQL::Maker) ⁃ validation in the Controller is preferable 31
  • 32. Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. Write fail-safe code  do not change the behavior based on the type of the input ⁃ instead, provide different method for each type of the input ⁃ e.g. sql_eq vs. sql_in 32
  • 33. Use blessed refs for dynamic behavior  use blessed refs in case you need to change the behavior based on the type of the input ⁃ this is a common idiom; many template engines use blessed refs to determine whether if a string is already HTML-escaped Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. # in case of Text::MicroTemplate sub escape_html { my $str = shift; return '' unless defined $str; return $str->as_string if ref $str eq 'Text::MicroTemplate::EncodedString'; $str =~ s/([&><"'])/$_escape_table{$1}/ge; return $str; } 33
  • 34. Use blessed refs for dynamic behavior (cont'd)  do not use serialization libraries with support for blessed objects (e.g. YAML or Storable) for user input ⁃ such use may lead to XSS or other code Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. injection vulnerability ⁃ always only accept scalars / arrays / hashes and validate their type and value 34
  • 35. Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. Thanks to  Toshiharu Sugiyama ⁃ original reporter of the issue ⁃ http://developers.mobage.jp/blog/2014/7/3/jsonsql-injection  @tokuhirom, @cho45 ⁃ for coordinating / working on the fix  @miyagawa ⁃ for the behavior of Catalyst, Ruby, etc.  @ockeghem ⁃ for looking into other impl. sharing the problem ⁃ http://blog.tokumaru.org/2014/07/json-sql-injectionphpjson. html 35