Module: NewRelic::Security::Agent::Utils
Constant Summary collapse
- ENABLED =
'enabled'- VULNERABLE =
'VULNERABLE'- AES_256_CBC =
'AES-256-CBC'- H_ASTERIK =
'H*'- ASTERISK =
'*'
Instance Method Summary collapse
- #app_port(env) ⇒ Object
- #app_root ⇒ Object
- #create_exit_event(event) ⇒ Object
- #decrypt_data(name, sha) ⇒ Object
- #delete_created_files(ctxt) ⇒ Object
- #disable_object_space_in_jruby ⇒ Object
- #enable_object_space_in_jruby ⇒ Object
- #filtered_log(log) ⇒ Object
- #get_app_routes(framework, router = nil) ⇒ Object
- #is_IAST? ⇒ Boolean
- #is_IAST_request?(headers) ⇒ Boolean
- #license_key ⇒ Object
- #parse_fuzz_header(ctxt) ⇒ Object
Instance Method Details
#app_port(env) ⇒ Object
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
# File 'lib/newrelic_security/agent/utils/agent_utils.rb', line 149 def app_port(env) listen_port = nil if env.key?('puma.socket') NewRelic::Security::Agent.config.app_server = :puma if env['puma.socket'].is_a?(TCPSocket) listen_port = env['puma.socket'].addr[1] NewRelic::Security::Agent.logger.debug "Detected port from puma.socket TCPSocket : #{listen_port}" elsif env['puma.socket'].is_a?(Puma::MiniSSL::Socket) listen_port = env['puma.socket'].instance_variable_get(:@socket).addr[1] NewRelic::Security::Agent.logger.debug "Detected port from puma.socket Puma::MiniSSL::Socket TCPSocket : #{listen_port}" end end if env.key?('unicorn.socket') && env['unicorn.socket'].is_a?(::Unicorn::TCPClient) NewRelic::Security::Agent.config.app_server = :unicorn listen_port, _ = ::Socket.unpack_sockaddr_in(env['unicorn.socket'].getsockname) NewRelic::Security::Agent.logger.debug "Detected port from unicorn.socket Unicorn::TCPClient : #{listen_port}" end ObjectSpace.each_object(::Falcon::Server) { |z| NewRelic::Security::Agent.config.app_server = :falcon listen_port = z.endpoint.instance_variable_get(:@specification)[1] NewRelic::Security::Agent.logger.debug "Detected port from Falcon::Server : #{listen_port}" } if defined?(::Falcon::Server) ObjectSpace.each_object(::Thin::Backends::TcpServer) { |z| NewRelic::Security::Agent.config.app_server = :thin listen_port = z.instance_variable_get(:@port) NewRelic::Security::Agent.logger.debug "Detected port from Thin::Backends::TcpServer : #{listen_port}" } if defined?(::Thin::Backends::TcpServer) ObjectSpace.each_object(::WEBrick::GenericServer) { |z| NewRelic::Security::Agent.config.app_server = :webrick listen_port = z.instance_variable_get(:@config)[:Port] NewRelic::Security::Agent.logger.debug "Detected port from WEBrick::GenericServer : #{listen_port}" } if defined?(::WEBrick::GenericServer) if NewRelic::Security::Agent.config[:'security.application_info.port'] != 0 listen_port = NewRelic::Security::Agent.config[:'security.application_info.port'] NewRelic::Security::Agent.logger.info "Using application listen port from newrelic.yml security.application_info.port : #{listen_port}" end if listen_port NewRelic::Security::Agent.logger.info "Detected application listen_port : #{listen_port}" else NewRelic::Security::Agent.logger.warn "Unable to detect application listen port, IAST can not run without application listen port. Please provide application listen port in security.application_info.port in newrelic.yml" end disable_object_space_in_jruby if NewRelic::Security::Agent.config[:jruby_objectspace_enabled] listen_port rescue Exception => exception NewRelic::Security::Agent.logger.error "Exception in port detection : #{exception.inspect} #{exception.backtrace}" end |
#app_root ⇒ Object
196 197 198 199 200 201 202 203 |
# File 'lib/newrelic_security/agent/utils/agent_utils.rb', line 196 def app_root #so far assuming it as Rails #TBD, determing the frame work then use appropriate APIs #val = Rails.root root = nil root = ::Rack::Directory.new(EMPTY_STRING).root.to_s if defined? ::Rack::Directory root end |
#create_exit_event(event) ⇒ Object
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/newrelic_security/agent/utils/agent_utils.rb', line 80 def create_exit_event(event) return unless event return unless is_IAST? return unless is_IAST_request?(event.httpRequest[:headers]) if event.httpRequest[:headers][NR_CSEC_FUZZ_REQUEST_ID].include?(event.apiId) && event.httpRequest[:headers][NR_CSEC_FUZZ_REQUEST_ID].include?(VULNERABLE) exit_event = NewRelic::Security::Agent::Control::ExitEvent.new exit_event.executionId = event.id exit_event.caseType = event.caseType exit_event.k2RequestIdentifier = event.httpRequest[:headers][NR_CSEC_FUZZ_REQUEST_ID] NewRelic::Security::Agent.agent.event_processor.send_exit_event(exit_event) end rescue Exception => exception NewRelic::Security::Agent.logger.error "Exception in create_exit_event: #{exception.inspect} #{exception.backtrace}" NewRelic::Security::Agent.agent.exit_event_stats.error_count.increment end |
#decrypt_data(name, sha) ⇒ Object
54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/newrelic_security/agent/utils/agent_utils.rb', line 54 def decrypt_data(name, sha) cipher = ::OpenSSL::Cipher.new AES_256_CBC cipher.decrypt cipher.key = NewRelic::Security::Agent.config[:extraction_key] decrypted = cipher.update [name].pack(H_ASTERIK) decrypted << cipher.final fname = decrypted[16..-1] return fname if ::Digest::SHA256.hexdigest(fname) == sha nil rescue Exception => exception NewRelic::Security::Agent.logger.error "Exception in decrypt_data: #{exception.inspect} #{exception.backtrace}" end |
#delete_created_files(ctxt) ⇒ Object
67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/newrelic_security/agent/utils/agent_utils.rb', line 67 def delete_created_files(ctxt) return unless ctxt headers = ctxt.headers if is_IAST? && is_IAST_request?(headers) ctxt.fuzz_files.each do |file| begin ::File.delete(file) rescue end end end end |
#disable_object_space_in_jruby ⇒ Object
212 213 214 215 216 217 |
# File 'lib/newrelic_security/agent/utils/agent_utils.rb', line 212 def disable_object_space_in_jruby if RUBY_ENGINE == 'jruby' && JRuby.respond_to?(:objectspace) && JRuby.objectspace JRuby.objectspace = false NewRelic::Security::Agent.config.jruby_objectspace_enabled = false end end |
#enable_object_space_in_jruby ⇒ Object
205 206 207 208 209 210 |
# File 'lib/newrelic_security/agent/utils/agent_utils.rb', line 205 def enable_object_space_in_jruby if RUBY_ENGINE == 'jruby' && JRuby.respond_to?(:objectspace) && !JRuby.objectspace JRuby.objectspace = true NewRelic::Security::Agent.config.jruby_objectspace_enabled = true end end |
#filtered_log(log) ⇒ Object
223 224 225 |
# File 'lib/newrelic_security/agent/utils/agent_utils.rb', line 223 def filtered_log(log) log.gsub(license_key, ASTERISK * license_key.size) end |
#get_app_routes(framework, router = nil) ⇒ Object
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/newrelic_security/agent/utils/agent_utils.rb', line 96 def get_app_routes(framework, router = nil) enable_object_space_in_jruby case framework when :rails ::Rails.application.routes.routes.each do |route| if route.verb.is_a?(::Regexp) method = route.verb.inspect.match(/[a-zA-Z]+/) NewRelic::Security::Agent.agent.route_map << "#{method}@#{route.path.spec.to_s.gsub(/\(\.:format\)/, "")}" if method else route.verb.split("|").each { |m| NewRelic::Security::Agent.agent.route_map << "#{m}@#{route.path.spec.to_s.gsub(/\(\.:format\)/, "")}" } end end when :sinatra ::Sinatra::Application.routes.each do |method, routes| routes.map { |r| r.first.to_s }.map do |route| NewRelic::Security::Agent.agent.route_map << "#{method}@#{route}" end end when :grape if defined?(::Grape::API) ObjectSpace.each_object(Class).select { |klass| klass < ::Grape::API }.each do |api_class| api_class.routes.each do |route| http_method = route.request_method || route.[:method] NewRelic::Security::Agent.agent.route_map << "#{http_method}@#{route.pattern.origin}" end end end when :padrino if router.instance_of?(::Padrino::PathRouter::Router) router.instance_variable_get(:@routes).each do |route| NewRelic::Security::Agent.agent.route_map << "#{route.instance_variable_get(:@verb)}@#{route.matcher.instance_variable_get(:@path)}" end end when :roda NewRelic::Security::Agent.logger.debug "TODO: Roda is a routing tree web toolkit, which generates route dynamically, hence route extraction is not possible." when :grpc router.owner.superclass.public_instance_methods(false).each do |m| NewRelic::Security::Agent.agent.route_map << "*@/#{router.owner}/#{m}" end when :rack # TODO: API enpointes(routes) extraction for rack else NewRelic::Security::Agent.logger.error "Unable to get app routes as Framework not detected" end disable_object_space_in_jruby if NewRelic::Security::Agent.config[:jruby_objectspace_enabled] NewRelic::Security::Agent.logger.debug "ALL ROUTES : #{NewRelic::Security::Agent.agent.route_map}" NewRelic::Security::Agent.agent.event_processor&.send_application_url_mappings unless NewRelic::Security::Agent.agent.route_map.empty? rescue Exception => exception NewRelic::Security::Agent.logger.error "Error in get app routes : #{exception.inspect} #{exception.backtrace}" end |
#is_IAST? ⇒ Boolean
17 18 19 20 |
# File 'lib/newrelic_security/agent/utils/agent_utils.rb', line 17 def is_IAST? return true if NewRelic::Security::Agent.config[:mode] == IAST false end |
#is_IAST_request?(headers) ⇒ Boolean
22 23 24 25 |
# File 'lib/newrelic_security/agent/utils/agent_utils.rb', line 22 def is_IAST_request?(headers) return true if headers&.key?(NR_CSEC_FUZZ_REQUEST_ID) false end |
#license_key ⇒ Object
219 220 221 |
# File 'lib/newrelic_security/agent/utils/agent_utils.rb', line 219 def license_key NewRelic::Security::Agent.config[:license_key] end |
#parse_fuzz_header(ctxt) ⇒ Object
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/newrelic_security/agent/utils/agent_utils.rb', line 27 def parse_fuzz_header(ctxt) headers = ctxt.headers if ctxt if is_IAST? && is_IAST_request?(headers) fuzz_request = headers[NR_CSEC_FUZZ_REQUEST_ID].split(COLON_IAST_COLON) if fuzz_request.length() >= 7 decrypted_data = decrypt_data(fuzz_request[6], fuzz_request[7]) if fuzz_request[6] && fuzz_request[7] && !fuzz_request[6].empty? && !fuzz_request[7].empty? if decrypted_data NewRelic::Security::Agent.logger.debug "Encrypted data: #{fuzz_request[6]}, decrypted data: #{decrypted_data}, Sha256: #{fuzz_request[7]}" decrypted_data.split(COMMA).each do |filename| begin filename.gsub!(NR_CSEC_VALIDATOR_HOME_TMP, NewRelic::Security::Agent.config[:fuzz_dir_path]) filename.gsub!(NR_CSEC_VALIDATOR_HOME_TMP_URL_ENCODED, NewRelic::Security::Agent.config[:fuzz_dir_path]) filename.gsub!(NR_CSEC_VALIDATOR_FILE_SEPARATOR, ::File::SEPARATOR) dirname = ::File.dirname(filename) ::FileUtils.mkdir_p(dirname, :mode => 0770) unless ::File.directory?(dirname) ctxt&.fuzz_files&.<< filename ::File.open(filename, ::File::WRONLY | ::File::CREAT | ::File::EXCL) do |fd| # puts "Ownership acquired by : #{Process.pid}" end unless ::File.exist?(filename) rescue end end end end end end |