validationPatterns = buildPatterns(SQL_REGEXPS);
61 |
62 | /**
63 | * Determines if the provided string value is SQL-Injection-safe.
64 | *
65 | * Empty value is considered safe.
66 | * This is used in by the SqlInjectionSafe annotation.
67 | *
68 | * @param dataString string value that is to verified
69 | * @return 'true' for safe and 'false' for unsafe
70 | */
71 | public static boolean isSqlInjectionSafe(String dataString){
72 | if(isEmpty(dataString)){
73 | return true;
74 | }
75 |
76 | for(Pattern pattern : validationPatterns){
77 | if(matches(pattern, dataString)){
78 | return false;
79 | }
80 | }
81 | return true;
82 | }
83 |
84 | private static boolean matches(Pattern pattern, String dataString){
85 | Matcher matcher = pattern.matcher(dataString);
86 | return matcher.matches();
87 | }
88 |
89 | private static List buildPatterns(String[] expressionStrings){
90 | List patterns = new ArrayList();
91 | for(String expression : expressionStrings){
92 | patterns.add(getPattern(expression));
93 | }
94 | return patterns;
95 | }
96 |
97 |
98 | private static Pattern getPattern(String regEx){
99 | return Pattern.compile(regEx, Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
100 | }
101 |
102 | private static boolean isEmpty(CharSequence cs) {
103 | return cs == null || cs.length() == 0;
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.github.rkpunjal.sqlsafe
7 | sql-injection-safe
8 | 1.0.2
9 | jar
10 |
11 | SQL-Injection-Safe Annotation
12 |
13 | This is an extremely lightweight library that provides
14 | an Annotation and a Utility class to verify if the provided string value is Sql-Injection-safe.
15 | This is backed by thorough and intelligent unit-tests.
16 |
17 | https://github.com/rkpunjal/sql-injection-safe
18 |
19 |
20 |
21 | MIT License
22 | http://www.opensource.org/licenses/mit-license.php
23 | repo
24 |
25 |
26 |
27 |
28 |
29 | Ramakrishna Punjal
30 | rkpunjal@gmail.com
31 |
32 |
33 |
34 |
35 | 1.8
36 | UTF-8
37 | 1.1.0.Final
38 | 4.12
39 |
40 |
41 |
42 | scm:git:git@github.com:rkpunjal/sql-injection-safe.git
43 | scm:git:git@github.com:rkpunjal/sql-injection-safe.git
44 | git@github.com:rkpunjal/sql-injection-safe.git
45 |
46 |
47 |
48 |
49 |
50 | javax.validation
51 | validation-api
52 | ${javax.validation.version}
53 |
54 |
55 |
56 | junit
57 | junit
58 | ${junit.version}
59 | test
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | ossrh
68 | https://oss.sonatype.org/content/repositories/snapshots
69 |
70 |
71 | ossrh
72 | https://oss.sonatype.org/service/local/staging/deploy/maven2/
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | org.sonatype.plugins
81 | nexus-staging-maven-plugin
82 | 1.6.7
83 | true
84 |
85 | ossrh
86 | https://oss.sonatype.org/
87 | false
88 |
89 |
90 |
91 |
92 | org.apache.maven.plugins
93 | maven-source-plugin
94 | 2.2.1
95 |
96 |
97 | attach-sources
98 |
99 | jar-no-fork
100 |
101 |
102 |
103 |
104 |
105 | org.apache.maven.plugins
106 | maven-javadoc-plugin
107 | 2.9.1
108 |
109 |
110 | attach-javadocs
111 |
112 | jar
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 | org.apache.maven.plugins
121 | maven-release-plugin
122 | 2.5
123 |
124 | false
125 | release
126 | deploy
127 |
128 |
129 |
130 |
131 | org.apache.maven.plugins
132 | maven-gpg-plugin
133 | 1.6
134 |
135 |
136 | sign-artifacts
137 | verify
138 |
139 | sign
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
--------------------------------------------------------------------------------
/src/test/java/com/github/rkpunjal/sqlsafe/SqlSafeUtilTest.java:
--------------------------------------------------------------------------------
1 | package com.github.rkpunjal.sqlsafe;
2 |
3 | import org.junit.Test;
4 |
5 | import java.util.regex.Matcher;
6 | import java.util.regex.Pattern;
7 |
8 | import static org.junit.Assert.assertFalse;
9 | import static org.junit.Assert.assertTrue;
10 |
11 | public class SqlSafeUtilTest {
12 |
13 | private static final String SPACES_REGEX = "[\\s|\\r|\\n|\\t]";
14 | private static final String EMPTY = "";
15 |
16 | @Test
17 | public void testWithBadData(){
18 | String[] maliciousDataSamples = {
19 | "select adf from abc",
20 | "insert into abcd",
21 | "update abcd",
22 | "delete from abcd",
23 | "upsert abcd",
24 | "call abcd",
25 | "rollback ",
26 | "create table abc",
27 | "drop table",
28 | "drop view",
29 | "alter table abc",
30 | "truncate table abc",
31 | "desc abc",
32 | "select id",
33 | "select 'abc'",
34 | };
35 |
36 | for(String maliciousPart : maliciousDataSamples){
37 | testUnSafeWithAllVariations(maliciousPart);
38 | }
39 |
40 |
41 | String[] sqlDisruptiveDataSamples = {
42 | "--",
43 | "/*",
44 | "*/",
45 | ";",
46 | "someone -- abcd",
47 | "abcd /* adf */ adf",
48 | };
49 |
50 |
51 | for(String desruptivePart : sqlDisruptiveDataSamples){
52 | testForPurelyUnSafeDataWithAllVariations(desruptivePart);
53 | }
54 |
55 |
56 |
57 | }
58 |
59 | @Test
60 | public void testWithGoodData(){
61 | String[] safeDataSamples = {
62 | "12",
63 | "abcd123",
64 | "123abcd",
65 | "abcd",
66 | " OR adfadfa adf column1 = COLUMN1",
67 | " and adfadfa adf column1 = COLUMN1",
68 | };
69 |
70 | for(String safeData : safeDataSamples){
71 | assertTrue("Failed to qualify this as SQL-injection safe data : " + safeData,
72 | SqlSafeUtil.isSqlInjectionSafe(safeData)
73 | );
74 | }
75 |
76 | }
77 |
78 | @Test
79 | public void testForEqualsInjection(){
80 |
81 | String[] maliciousSamples = {
82 | " OR false ",
83 | " OR true ",
84 | " and true ",
85 | " OR equals true ",
86 | " OR not equals true ",
87 | " OR equals false ",
88 | " and equals false ",
89 | " OR 1=1",
90 | " and 1=1",
91 | " OR column1=COLUMN1",
92 | " OR column1 = COLUMN1",
93 | " OR column1!=COLUMN1",
94 | " OR column1<>COLUMN1",
95 | " OR colu_mn1=COL_UMN1",
96 | " OR 'A'='A'",
97 | " OR '1afA'='2fadfA'",
98 | " OR 1=1 OR 2=2",
99 | " OR 1=1 and 2=2",
100 | " and 1=1 and 2=2",
101 | " and 1=1 or 2=2",
102 | };
103 |
104 | for(String maliciousData : maliciousSamples){
105 | testForPurelyUnSafeDataWithAllVariationsExcludeEmptySpacesCheck(maliciousData);
106 | }
107 |
108 | }
109 |
110 |
111 | private void testUnSafeWithAllVariations(String maliciousPart) {
112 | String prefix = "some-Data-prefix";
113 | String suffix = "some-Data-suffix";
114 | String space = " ";
115 |
116 | String maliciousData = "";
117 | String safeData = "";
118 |
119 | maliciousData = prefix + space + maliciousPart + space + suffix;
120 |
121 | assertFalse("Failed to detect SQL-unsafe data : " + maliciousData,
122 | SqlSafeUtil.isSqlInjectionSafe(maliciousData)
123 | );
124 |
125 | assertFalse("Failed to detect SQL-unsafe data : " + maliciousData.toUpperCase(),
126 | SqlSafeUtil.isSqlInjectionSafe(maliciousData.toUpperCase())
127 | );
128 |
129 | safeData = prefix + maliciousPart + suffix;
130 |
131 | assertTrue("Failed to qualify this as SQL-injection safe data : " + safeData,
132 | SqlSafeUtil.isSqlInjectionSafe(safeData)
133 | );
134 |
135 | safeData = removeAllSpaces(maliciousData);
136 | assertTrue("Failed to qualify this as SQL-injection safe data : " + safeData,
137 | SqlSafeUtil.isSqlInjectionSafe(safeData)
138 | );
139 |
140 | prefix = "";
141 | suffix = "";
142 | maliciousData = prefix + maliciousPart + suffix;
143 |
144 | assertFalse("Failed to detect SQL-unsafe data : " + maliciousData,
145 | SqlSafeUtil.isSqlInjectionSafe(maliciousData)
146 | );
147 |
148 |
149 | safeData = removeAllSpaces(maliciousData);
150 | assertTrue("Failed to qualify this as SQL-injection safe data : " + safeData,
151 | SqlSafeUtil.isSqlInjectionSafe(safeData)
152 | );
153 |
154 | }
155 |
156 | private void testForPurelyUnSafeDataWithAllVariations(String maliciousPart, boolean emptySpaceCheckRequired) {
157 | String prefix = "some-Data-prefix";
158 | String suffix = "some-Data-suffix";
159 | String space = " ";
160 |
161 | String maliciousData = "";
162 | String safeData = "";
163 |
164 | maliciousData = prefix + space + maliciousPart + space + suffix;
165 |
166 | assertFalse("Failed to detect SQL-unsafe data : " + maliciousData,
167 | SqlSafeUtil.isSqlInjectionSafe(maliciousData)
168 | );
169 |
170 | assertFalse("Failed to detect SQL-unsafe data : " + maliciousData.toUpperCase(),
171 | SqlSafeUtil.isSqlInjectionSafe(maliciousData.toUpperCase())
172 | );
173 |
174 | if(emptySpaceCheckRequired) {
175 | assertFalse("Failed to detect SQL-unsafe data : " + removeAllSpaces(maliciousData),
176 | SqlSafeUtil.isSqlInjectionSafe(removeAllSpaces(maliciousData))
177 | );
178 | }
179 |
180 | prefix = "";
181 | suffix = "";
182 | maliciousData = prefix + maliciousPart + suffix;
183 |
184 | assertFalse("Failed to detect SQL-unsafe data : " + maliciousData,
185 | SqlSafeUtil.isSqlInjectionSafe(maliciousData)
186 | );
187 |
188 | if(emptySpaceCheckRequired){
189 | assertFalse("Failed to detect SQL-unsafe data : " + removeAllSpaces(maliciousData),
190 | SqlSafeUtil.isSqlInjectionSafe(removeAllSpaces(maliciousData))
191 | );
192 | }
193 |
194 | }
195 |
196 | private void testForPurelyUnSafeDataWithAllVariations(String maliciousPart) {
197 | testForPurelyUnSafeDataWithAllVariations(maliciousPart, true);
198 | }
199 |
200 |
201 | private void testForPurelyUnSafeDataWithAllVariationsExcludeEmptySpacesCheck(String maliciousPart) {
202 | testForPurelyUnSafeDataWithAllVariations(maliciousPart, false);
203 |
204 | }
205 |
206 | private String removeAllSpaces(String str){
207 | Pattern pattern = Pattern.compile(SPACES_REGEX);
208 | Matcher matcher = pattern.matcher(str);
209 | return matcher.replaceAll(EMPTY);
210 | }
211 |
212 | }
213 |
214 |
215 |
--------------------------------------------------------------------------------