summaryrefslogtreecommitdiffhomepage
path: root/lib
diff options
context:
space:
mode:
authorGabriel Morcote <[email protected]>2019-12-20 15:01:35 -0600
committerStefan Daschek <[email protected]>2019-12-20 22:01:35 +0100
commit0a223011a26949ddc00eba882005daee7afeb6a6 (patch)
treea5ffc3459f43e0efef8326dbd1738cac5c5dbc0f /lib
parent99d3d2fbe5b07aa005b475b8cdc4e6238c3d5e28 (diff)
downloadcaxlsx-0a223011a26949ddc00eba882005daee7afeb6a6.tar.gz
caxlsx-0a223011a26949ddc00eba882005daee7afeb6a6.zip
Add option to protect against formula injection attacks (#34)
Caxlsx used to treat cell values beginning with an equal sign as formula by default. This can be dangerous if the input data is user generated or coming from other untrusted sources (see https://www.owasp.org/index.php/CSV_Injection for details). This commit adds a new option `escape_formulas` that can be used with `#add_row` and on instances of `Cell`. If set to true, cell values beginning with an equal sign are treated as normal strings (and will be displayed literally by Excel and co.)
Diffstat (limited to 'lib')
-rw-r--r--lib/axlsx/workbook/worksheet/cell.rb20
-rw-r--r--lib/axlsx/workbook/worksheet/row.rb3
-rw-r--r--lib/axlsx/workbook/worksheet/worksheet.rb10
3 files changed, 32 insertions, 1 deletions
diff --git a/lib/axlsx/workbook/worksheet/cell.rb b/lib/axlsx/workbook/worksheet/cell.rb
index 99b3f8b0..53bea28b 100644
--- a/lib/axlsx/workbook/worksheet/cell.rb
+++ b/lib/axlsx/workbook/worksheet/cell.rb
@@ -30,6 +30,10 @@ module Axlsx
# @option options [String] color an 8 letter rgb specification
# @option options [Number] formula_value The value to cache for a formula cell.
# @option options [Symbol] scheme must be one of :none, major, :minor
+ # @option options [Boolean] escape_formulas - Whether to treat a value starting with an equal
+ # sign as formula (default) or as simple string.
+ # Allowing user generated data to be interpreted as formulas can be dangerous
+ # (see https://www.owasp.org/index.php/CSV_Injection for details).
def initialize(row, value = nil, options = {})
@row = row
# Do not use instance vars if not needed to use less RAM
@@ -38,6 +42,8 @@ module Axlsx
type = options.delete(:type) || cell_type_from_value(value)
self.type = type unless type == :string
+ escape_formulas = options[:escape_formulas]
+ self.escape_formulas = escape_formulas unless escape_formulas.nil?
val = options.delete(:style)
self.style = val unless val.nil? || val == 0
@@ -102,6 +108,18 @@ module Axlsx
self.value = @value unless !defined?(@value) || @value.nil?
end
+ # Whether to treat a value starting with an equal
+ # sign as formula (default) or as simple string.
+ # Allowing user generated data to be interpreted as formulas can be dangerous
+ # (see https://www.owasp.org/index.php/CSV_Injection for details).
+ # @return [Boolean]
+ attr_reader :escape_formulas
+
+ def escape_formulas=(v)
+ Axlsx.validate_boolean(v)
+ @escape_formulas = v
+ end
+
# The value of this cell.
# @return [String, Integer, Float, Time, Boolean] casted value based on cell's type attribute.
attr_reader :value
@@ -324,6 +342,8 @@ module Axlsx
end
def is_formula?
+ return false if escape_formulas
+
type == :string && @value.to_s.start_with?(?=)
end
diff --git a/lib/axlsx/workbook/worksheet/row.rb b/lib/axlsx/workbook/worksheet/row.rb
index b394279f..decd27c7 100644
--- a/lib/axlsx/workbook/worksheet/row.rb
+++ b/lib/axlsx/workbook/worksheet/row.rb
@@ -147,10 +147,11 @@ module Axlsx
# @option options [Array, Integer] style
def array_to_cells(values, options={})
DataTypeValidator.validate :array_to_cells, Array, values
- types, style, formula_values = options.delete(:types), options.delete(:style), options.delete(:formula_values)
+ types, style, formula_values, escape_formulas = options.delete(:types), options.delete(:style), options.delete(:formula_values), options.delete(:escape_formulas)
values.each_with_index do |value, index|
options[:style] = style.is_a?(Array) ? style[index] : style if style
options[:type] = types.is_a?(Array) ? types[index] : types if types
+ options[:escape_formulas] = escape_formulas.is_a?(Array) ? escape_formulas[index] : escape_formulas if escape_formulas
options[:formula_value] = formula_values[index] if formula_values.is_a?(Array)
self[index] = Cell.new(self, value, options)
diff --git a/lib/axlsx/workbook/worksheet/worksheet.rb b/lib/axlsx/workbook/worksheet/worksheet.rb
index 9cfefa51..4fb95d4c 100644
--- a/lib/axlsx/workbook/worksheet/worksheet.rb
+++ b/lib/axlsx/workbook/worksheet/worksheet.rb
@@ -390,6 +390,12 @@ module Axlsx
# @example - use << alias
# ws << [3, 4, 5], :types => [nil, :float]
#
+ # @example - specify whether a row should escape formulas or not
+ # ws.add_row ['=IF(2+2=4,4,5)', 2, 3], :escape_formulas=>true
+ #
+ # @example - specify whether a certain cells in a row should escape formulas or not
+ # ws.add_row ['=IF(2+2=4,4,5)', '=IF(13+13=4,4,5)'], :escape_formulas=>[true, false]
+ #
# @see Worksheet#column_widths
# @return [Row]
# @option options [Array] values
@@ -397,6 +403,10 @@ module Axlsx
# @option options [Array, Integer] style
# @option options [Array] widths each member of the widths array will affect how auto_fit behavies.
# @option options [Float] height the row's height (in points)
+ # @option options [Array, Boolean] escape_formulas - Whether to treat a value starting with an equal
+ # sign as formula (default) or as simple string.
+ # Allowing user generated data to be interpreted as formulas can be dangerous
+ # (see https://www.owasp.org/index.php/CSV_Injection for details).
def add_row(values=[], options={})
row = Row.new(self, values, options)
update_column_info row, options.delete(:widths)